文档章节

一种处理栈越界的方法

悬崖
 悬崖
发布于 2016/04/14 11:00
字数 1688
阅读 111
收藏 1
点赞 1
评论 0

作者:吉林小伙
链接:http://zhuanlan.zhihu.com/p/20642841
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在linux下,栈越界写坏返回地址会导致调用栈无法回溯,这就导致我们直接使用bt没有办法查看崩溃时调用栈,今天我讲一下我最近研究出来的一种方法(虽然是原创,但可能互联网上早有人发布过此种方法,只不过我没有查到而已).

废话少说,步入正题,首先我写了个简单的程序来构造一个栈溢出的情况,为了使效果更加明显,我使用了一些递归来增加调用栈的深度,代码如下:

不要吐槽命名方式,我也知道很丑,栈都能越界的程序,一定漂亮不到哪去,哈哈!

简单描述下这个代码的功能,func2里递归调用了func2,这样能有效增加调用栈深度,然后调用func3的时候,由于func3里写buf越界了,导致栈被破坏了,然后段错误崩溃.崩溃后生成了core文件,我们用gdb打开,输入bt,效果如下:

由于栈破坏有很多种方式,bt也有可能显示出一排??,总之栈破坏很有可能导致bt无法回溯就是了.那我们如何应对呢?我们首先来看一下调用栈的一些知识:

一般情况下,在调用函数之前,(部分)参数会放入栈内,然后执行汇编指令call, 执行call后会自动将返回地址压入栈中,然后执行被调用函数,被调用函数开头的两条汇编指令很可能是:
push rbp
mov  rbp,rsp
这两条指令的作用就是把rbp压入栈中,把栈顶指针rsp赋值给rbp,这样在栈内就会形成一个 链表,以便我们回溯调用栈.
注意:
在开启优化的时候,默认是 -fomit-frame-pointer,这样可能导致很多函数开头不会出现那两条汇编指令,-fno-omit-frame-pointer选项开启后就会生成以上两条指令.

好了,详细的栈资料请大家自行查阅资料学习,我就不再赘述了.你只要知道调用栈在栈内是以链表的方式保存即可.那栈越界写坏的地方我们可以认为是链表的头部,由于链表的头部被写坏了,导致gdb的bt指令无法回溯调用栈了.

既然如此,那我们可以再找一个节点作为链表的头部.只不过回溯的调用栈可能比"完美"的调用栈少那么一两条,不过半个面包总比没有好,说干就干:

上图的代码是gdb的扩展,我扩展了一个bts(backtrace stack)指令,其作用是打印给定addr后的count条内容.gdb中可以使用source指令来加载扩展,也可以在home路径下新建.gdbinit文件,将脚本内容写入,这样在gdb启动时就会自动生效,我们使用source .gdbinit来加载一个这个bts扩展指令.然后在gdb里输入i r rsp指令:

,rsp的值一般情况下是栈顶,不过不排除这个值是不对的,只是不对的概率比较小而已,然后键入指令:

(gdb) set pagination off
(gdb) set loggin on ./log
Copying output to ./log.
(gdb)bts 0x7fff81f7c250 1000

第一条指令的作用是关闭"超过一屏内容等待键入回车"功能,第二条是打开log,这样gdb里的输出就会写入log文件内,第三条就是我们写的扩展指令了,执行一下,等待结果写入到文件中吧.由于我们的测试程序很短,栈也没用多大,所以1000应该就可以了,实际程序中这个1000可能要变得很大,可能要跑几分钟,不过我很享受这几分钟,因为我就喜欢敲入一条命令然后屏幕刷刷滚的感觉,逼格高,哈哈!!

跑题了,好了,输出结束我们去看看./log文件,执行head ./log命令,结果如下:

这正是我们想要的内容,第一列是栈地址,第二列是该地址的内容,既然调用栈在栈内是链表,那我们就可以写个代码把栈内所有的链表都暴力搜出来,然后看下哪个最可能是调用栈.

这是我写的暴力搜索栈中链表的程序,其实大家完全可以用脚本写,比c++方便多了.好了,g++ stack.cpp -o stack编译一下,然后执行:

./stack log 100 > symbol

log就是我们的log文件了,100呢是调用栈的深度,当你指定100的时候,会把所有调用栈深度为100的链表打印出来,由于我们递归超过100次了,所以这里我就指定100了,如果你在实际应用中,100没有结果,那可以尝试逐渐减小这个数值,然后我们看看symbol里的内容:

大概是这样的,还有好多条,我只截取了部分,之所以有info symbol,是因为我要在gdb中加载这个symbol文件,加载后会自动执行info symbol address,作用就是打印出这条地址附近的符号:

(gdb)source ./symbol

此处应该有掌声!!!

从下往上看,依次是__libc_start_main()->main()->func1()->func2()...,这的确是我们程序中的调用栈,只不过丢失了func3而已.

最后总结一下,此片专栏只是提供一种解决方法而已,具体能否成功,要看运气了.我一直觉得调试找bug是要看运气的,尤其是那些偶然出现的crash,在你不知道原因无法重现时只能从core dump里寻找蛛丝马迹了.

经验:一般栈越界很有可能是字符串越界,此时可以查看rsp附近的内存,说不定有很明显的字符串,一下就定位问题了呢.

由于水平有限,文章中有错误在所难免,请大家包含并指教,谢谢!

-----------------------------------------------

更新一下暴力搜索调用栈的那个代码,其中有一处bug可能导致在遍历调用栈的时候死循环.更新后如上图所示,这样就不怕栈里有回路了,还有一处修改,这个地方用sizeof(void*),就兼容32bit 64bit的程序了,以前写的8只支持64bit的程序


© 著作权归作者所有

共有 人打赏支持
悬崖
粉丝 3
博文 37
码字总数 22549
作品 0
海淀
程序员
3.10 在机器级程序中将控制与数据结合起来

3.10.1 理解指针 指针是C语言的一个核心特色,它提供了一种统一方式,对不同数据结构中的元素产生引用。 每个指针都对应一个类型,void *类型代表通用指针,它通过强制或隐式类型转换变成一个...

ShutLove ⋅ 04/20 ⋅ 0

Java数据结构与算法(三)-栈和队列

1.栈 先进后出,后进先出 栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素...

FantJ ⋅ 2017/12/21 ⋅ 0

Xcode 断点调试

基本断点 如下图,这种是最常用的断点,也是最容易设置。左键点击一下就可以设置。 编辑断点 断点是可以编辑的。 断点有下面几个属性可以设置: Condition Ignore Action Options Condition ...

夕阳_jhe ⋅ 2015/08/11 ⋅ 0

Java十大低级错误

1、Java十大低级错误 不能用"=="比较两个字符串内容相等。 对list做foreach循环时,循环代码中不能修改list的结构。 日志和实际情况不一致;捕获异常后没有在日志中记录异常栈。 魔鬼数字。 ...

周东尧 ⋅ 2016/03/30 ⋅ 2

只会左键断点?是时候试试这样那样断点了

文本是投稿文章,作者:空之境界(博客) 编码不能没调试,调试不能没断点(Break Point)。XCode的断点功能也是越来越强大。 基本断点 如下图,这种是最常用的断点,也是最容易设置。左键点...

TomatosX ⋅ 2015/08/01 ⋅ 0

腾讯御见捕获Flash 0day漏洞(CVE-2018-5002)野外攻击

  0×1 概述   腾讯御见威胁情报中心近日监控到一例使用Adobe Flash 0day漏洞(CVE-2018-5002)的APT攻击,攻击者疑通过即时聊天工具和邮箱等把恶意Excel文档发送给目标人员,诱骗目标人...

FreeBuf ⋅ 06/09 ⋅ 0

Stack OverFlow 栈溢出 - stack smashing detected

在改造一个otatsgenerator工具时,调试时,发生如下错误: ./app stack smashing detected **: ./app terminated======= Backtrace: =========/lib/tls/i686/cmov/libc.so.6(fortify_fail+0x......

地狱的烈火 ⋅ 2013/07/22 ⋅ 0

汇编语言-第三章 寄存器(栈存储)

3.6 栈 栈是一种具有特殊的访问方式的存储空间。 栈有两个最基本的操作:入栈和出栈。 栈的操作规则为:LIFO(后进先出,Last In First Out) 3.7 CPU提供的栈机制 现今的CPU中都有栈的设计。...

Frost729 ⋅ 02/09 ⋅ 0

异常相关概念

[x] Error 和 Exception有什么区别 [x] 什么是受检查的异常,什么是运行时异常 运行时异常与一般异常有何异同 [ ] 什么是异常链 [x] throw 和 throws 有什么区别? [ ] 简述一个你最常见到的...

AmorFatiYJ ⋅ 2017/12/22 ⋅ 0

为什么栈中的数组越界后经常不崩溃,还可以正常的操作呢

使用数组也是家常便饭,但是经常出现越界使用数组也能编译通过的奇怪问题,和我们书中学习的很不一样,怎么折腾也不知道为什么,郁闷了吧!哈哈哈,别慌,这里就给你答案啦。 函数中分配的数...

hejunbinlan ⋅ 2016/11/29 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

RabbitMQ学习以及与Spring的集成(三)

本文介绍RabbitMQ与Spring的简单集成以及消息的发送和接收。 在RabbitMQ的Spring配置文件中,首先需要增加命名空间。 xmlns:rabbit="http://www.springframework.org/schema/rabbit" 其次是模...

onedotdot ⋅ 15分钟前 ⋅ 0

JAVA实现仿微信红包分配规则

最近过年发红包拜年成为一种新的潮流,作为程序猿对算法的好奇远远要大于对红包的好奇,这里介绍一种自己想到的一种随机红包分配策略,还请大家多多指教。 算法介绍 一、红包金额限制 对于微...

楠木楠 ⋅ 27分钟前 ⋅ 0

Python 数电表格格式化 xlutils xlwt xlrd的使用

需要安装 xlutils xlwt xlrd 格式化前 格式化后 代码 先copy读取的表格,然后按照一定的规则修改,将昵称中的学号提取出来替换昵称即可 from xlrd import open_workbookfrom xlutils.copy ...

阿豪boy ⋅ 56分钟前 ⋅ 0

面试题:使用rand5()生成rand7()

前言 读研究生这3 年,思维与本科相比变化挺大的,这几年除了看论文、设计方案,更重要的是学会注重先思考、再实现,感觉更加成熟吧,不再像个小P孩,人年轻时总会心高气傲。有1 道面试题:给...

初雪之音 ⋅ 57分钟前 ⋅ 0

Docker Toolbox Looks like something went wrong

Docker Toolbox 重新安装后提示错误:Looks like something went wrong in step ´Checking if machine default exists´ 控制面板-->程序与应用-->启用或关闭windows功能:找到Hyper-V,如果处......

随你疯 ⋅ 今天 ⋅ 0

Guacamole 远程桌面

本文将Apache的guacamole服务的部署和应用,http://guacamole.apache.org/doc/gug/ 该链接下有全部相关知识的英文文档,如果水平ok,可以去这里仔细查看。 一、简介 Apache Guacamole 是无客...

千里明月 ⋅ 今天 ⋅ 0

nagios 安装

Nagios简介:监控网络并排除网络故障的工具:nagios,Ntop,OpenVAS,OCS,OSSIM等开源监控工具。 可以实现对网络上的服务器进行全面的监控,包括服务(apache、mysql、ntp、ftp、disk、qmail和h...

寰宇01 ⋅ 今天 ⋅ 0

AngularDart注意事项

默认情况下创建Dart项目应出现以下列表: 有时会因为不知明的原因导致列表项缺失: 此时可以通过以下步骤解决: 1.创建项目涉及到的包:stagehand 2.执行pub global activate stagehand或pub...

scooplol ⋅ 今天 ⋅ 0

Java Web如何操作Cookie的添加修改和删除

创建Cookie对象 Cookie cookie = new Cookie("id", "1"); 修改Cookie值 cookie.setValue("2"); 设置Cookie有效期和删除Cookie cookie.setMaxAge(24*60*60); // Cookie有效时间 co......

二营长意大利炮 ⋅ 今天 ⋅ 0

【每天一个JQuery特效】淡入淡出显示或隐藏窗口

我是JQuery新手爱好者,有时间就练练代码,防止手生,争取每天一个JQuery练习,在这个博客记录下学习的笔记。 本特效主要采用fadeIn()和fadeOut()方法显示淡入淡出的显示效果显示或隐藏元...

Rhymo-Wu ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部