首页 > 编程语言 >从汇编层看64位程序运行——有惊无险的栈溢出

从汇编层看64位程序运行——有惊无险的栈溢出

时间:2024-08-12 18:57:56浏览次数:11  
标签:foo 函数 程序运行 rbp 有惊无险 寄存器 64 main rsp

大纲

《从汇编层看64位程序运行——ROP攻击以控制程序执行流程》一文中,我们通过“篡改”函数的返回地址来达成修改程序执行流程的目的。
在这里插入图片描述

但是这个方案存在一个问题:它会导致栈溢出。这是因为ret指令会导致栈的pop,call指令会导致栈的push。而案例中,foo7调用foo函数时,使用的是ROP攻击方法——没有使用call指令。这样就导致整个流程call了1次(main–>foo7),即压栈1次;而ret了2次,foo7一次,foo一次。

在foo7进入foo之后,我们修改了foo的返回地址。这个地址是0x7fffffffdef8,而它属于main函数的栈帧。这样的栈溢出,并没有导致我们程序出问题。这是因为0x7fffffffdef8保存的是main函数调用foo7时,push到栈中的临时数据(即第7个参数,foo函数的地址)。所以在从foo回到main函数后,这个空间的值就不会被逻辑所使用,进而没有发生问题。

但是由于call一次、ret两次,最终会导致栈会被多pop一次。于是回到main函数后,rsp的值会比正确的时候大0x08(即main的栈帧小了0x08),而减小的空间正好是上一段分析的main函数push到foo7中的foo函数地址。
我们知道,很多时候栈上变量的表达是通过rbp寄存器(rbp寄存器的值一直是正确的)来进行的(见《从汇编层看64位程序运行——栈上变量的rbp表达》),所以这次rsp寄存器的变动,一般不会影响main函数临时变量的取值,也不会影响程序执行。

即使后面调用了其他函数,甚至push栈传递数据的行为,也不会造成程序的崩溃。这是因为此时rsp指向了main函数栈上变量地址空间的末尾。调用其他函数时,只会让栈在此基础上增长,并不会影响到main函数关键的栈帧空间。
在这里插入图片描述

从main函数退出时,汇编会执行Leave指令。这步指令会

mv %rbp,%rsp

这样rsp寄存器的值就回到进入main函数时正确的值,进而导致代码进入main函数的调用者时,堆栈由恢复到正确的状态,所以程序也没有出问题。

整体调试过程如下:

main

进入时寄存器状态

rbp:1

rsp:df18

分析过程

刚进入main函数时,栈底寄存器rbp的值是1,栈顶寄存器rsp的值是df18。
在这里插入图片描述
+4行将rbp寄存器的值压入栈后,栈顶寄存器rsp的值变成df10。
+5行让rbp和rsp寄存器中的值相同,即rbp和rsp都是df10。
+8行预先给main函数分配了栈空间(0x10)。这样rsp变成df00,rbp还是df10。
在这里插入图片描述
+23行会foo函数的地址压入栈,这样rsp会变成def8。(0x7fffffffdef8,即后续在foo函数中被用作返回RIP的空间。)
在这里插入图片描述

离开时寄存器状态

rbp:df10

rsp:def8

foo7

进入时寄存器状态

rbp:df10

rsp:def8

分析过程

执行call指令,进入foo函数内部。由于call会将next_rip压入栈,所以rsp的值会继续减少0x08,变成def0。
在这里插入图片描述
可以看到栈顶的值就是next_rip的值。
在这里插入图片描述
将main函数的栈底寄存器的值保存到栈上,这样rsp变成了dee8。
在这里插入图片描述
此时的栈顶rsp就是可以用于给foo7函数预分配栈上空间的值。但是由于要用rbp做变量表达转换,所以会将rbp的值赋值为rsp的值。这样rbp和rsp的值都是dee8了。
在这里插入图片描述
由于中间过程没有进入出入栈的操作,所以一直到+75行,rsp和rbp的值都没变。
在这里插入图片描述
但是我们修改了栈上空间的值,即foo7的返回地址,
在这里插入图片描述
+75会抛出之前保存的rbp的值,这样rbp的值会还原到df10;同时rip会退栈,变成def0。
在这里插入图片描述
这样,foo7的返回地址(foo函数的入口地址)就处于栈的顶端。
在这里插入图片描述

离开时寄存器状态

rbp:df10

rsp:def0

foo

进入时寄存器状态

rbp:df10

rsp:def8

分析过程

foo7最后的ret会从栈中pop出next_rip,然后跳转到foo。这样退栈行为,让rsp变成def8。
在这里插入图片描述
+4行,会将rbp压入栈,这样rsp变成了def0。
在这里插入图片描述
+5行会让rbp等于rsp。这样foo函数就会可以在自己的栈底上分配空间和修改变量。
在这里插入图片描述
+8行会给foo函数分配0x10大小的栈上空间。这样rsp的值就会变成dee0。
在这里插入图片描述
+12和+16行分别会赋值一个栈上变量以及修改foo函数的返回地址
在这里插入图片描述
打印输出函数执行完,栈的状态没有变
在这里插入图片描述
+36行的Leave做了几件事:

  • mov %rbp, %rsp。即还原栈顶寄存器(对应于+5行),这样rsp变成def0。
  • pop %rbp。这样保存在栈顶def0的df10会被赋值给rbp。而rsp也因为退栈,从而变成了def8。
    在这里插入图片描述

离开时寄存器状态

rbp:df10

rsp:def8

main

进入时寄存器状态

rbp:df10

rsp:df00

分析过程

foo最后的ret会将foo的next_rip(即51fb)从栈中pop出来,这样rsp进一步变成了df00。

再次回到main函数后,rsp的值不再是离开main是的def8。
在这里插入图片描述
+63行又会让rsp进一步改变,变成df08。
在这里插入图片描述
+72的Leave,会干两件事:

  • mov %rbp, %rsp。还原栈顶寄存器(对应于+5行)。这样rsp变成df10。
  • pop出rbp。rsp变成df18。rbp变成1。
    在这里插入图片描述

离开时寄存器状态

rbp:1

rsp:df18

标签:foo,函数,程序运行,rbp,有惊无险,寄存器,64,main,rsp
From: https://blog.csdn.net/breaksoftware/article/details/140825373

相关文章

  • Microsoft 365(Office 365)ProPlus x64 v16.0.18007.20000 特别版
    概述Microsoft365是微软公司推出的一款集成办公套件软件,整合了Office应用程序、云存储、电子邮件服务以及其他生产力工具,旨在为个人和企业用户提供全面且便捷的办公解决方案。软件功能Office应用程序:Microsoft365包括常见的Office应用程序,如Word、Excel、PowerPoint和Outloo......
  • polyfill base64 atob and btoa
     https://github.com/MaxArt2501/base64-js (function(root,factory){if(typeofdefine==='function'&&define.amd){//AMD.Registerasananonymousmodule.define([],function(){factory(root);});}elsef......
  • springboot社区食堂管理平台-计算机毕业设计源码86404
    目 录1绪论1.1研究背景1.2研究意义1.3论文结构与章节安排2 社区食堂管理平台系统分析2.1可行性分析2.2系统流程分析2.2.1 数据流程3.3.2 业务流程2.3 系统功能分析2.3.1功能性分析2.3.2非功能性分析2.4 系统用例分析2.5本章小结3......
  • base64加密解密,中文乱码问题
    base64加密解密,中文乱码问题通常的方法是通过window.btoa()方法对源数据进行编码,然后接收方使用window.atob()方法对其进行解码,从而得到原数据.由于btoa方法仅支持ASCII编码,我们在转换中文的时候就需要先将中文转换为ASCII字符序列,再通过btoa进行base64编码,......
  • vs2022 x64 C/C++和汇编混编 遇到的坑
    vs2022x64C/C++和汇编混编遇到的坑遇到的问题二、问题复现1.出错代码2.问题分析2.1堆栈对齐问题3.解决方案总结奇数和偶数个寄存器的影响为什么`subrsp,8`对奇数个寄存器有用?结论遇到的问题0x00007FFFFAE24A29(msvcp140.dll)处(位于TestCompileConsol......
  • Nexpose v6.6.264 for Linux & Windows - 漏洞扫描
    Nexposev6.6.264forLinux&Windows-漏洞扫描Rapid7VulnerabilityManagement,releaseAug07,2024请访问原文链接:https://sysin.org/blog/nexpose-6/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org您的本地漏洞扫描程序搜集通过实时覆盖整个网络,随......
  • CF1264E Beautiful League 题解
    CF1264E你有一张竞赛图,给你竞赛图中\(m\)条边的方向,让你对于没有给定的边确定方向使得整张图的三元环个数最多\(n\leq50,m\leq\frac{(n-1)n}{2}\)费用流好题三元环是一个非常难考虑的东西,我们考虑求他的补集:不是三元环的个数最少我们发现不是三元环的情况是存......
  • C++虚函数表、地址详解(x86/x64)
    参考博文:c++虚函数表、地址详解-CSDN博客本文在上述博文的基础上,补充了x64下的验证代码。一.什么是虚函数表,它有什么特点?        虚函数大家都知道是基本用于实现多态的,当父类指针指向子类对象的时候,如何确定调用的函数是父类里的还是子类里面的,这就要用到虚函数表......
  • VDI/VDE 2643 Part3 2008:10
    [!NOTE]原始PDF链接:https://www.doc88.com/p-50359701027029.htmlOptical3D-measuringsystemsMultipleviewsystemsbasedonareascanningPreliminarynoteThecontentofthisguidelinehasbeendevelopedinstrictaccordancewiththerequirementsandrecomme......
  • 渗透测试基础及x64dbg调试器
    一、实验原理x64dbg是一款开源且免费的Ring3级动态调试器,采用QT编写,支持32/64位程序。其反汇编引擎BeaEngine和Capstone功能极其强大,也有丰富的插件和脚本功能,且并保持更新,目前已经基本替代了OllDbg。软件解压后根目录存在x96dbg,双击x96dbg,出现三个弹窗,会......