1、程序编译,链接后生成二进制可执行程序。二进制可执行文件以elf格式实现排列。可以通过readelf -S xxxx查看具体section的划分,粗略划分如下图所示。
在这些section中,代码段是只读的,自然也就不存在代码(指令)被改写的情况。数据段,堆,栈区具有读写的属性,但是数据段和堆一般存放的是数据,不涉及到指令的问题。剩下的栈区,存放的既有数据,又有代码(指令),可能存在代码(指令)被改写,即内存被飞踩现象。
2、栈空间数据被修改情况
2.1、先做个实验(ARM 32环境)
2.1.1、栈区空间
查看反汇编结果
增加max函数的局部变量个数,再查看相对应的反汇编
由此可见,栈区的大小在程序编译的时候就已经确定。存放着函数退出后下一条指令的地址和局部变量的数值。
2.1.2、栈区数据
从局部变量中,获取栈区地址,打印栈区里面的部分数据。
第一个红框存放着局部变量的数据,第二个红框存放着退出函数后下一条指令的地址,可以从反汇编中确认。
2.1.3、修改栈区数据,其中存放的下一条指令的地址0x10545被改写,程序运行是不是就会出现异常。
上图截图中绿框所示,对应着是另外一个函数do_nothing的地址,假如把栈区0x10545的数据改写成do_nothing的地址,应该就会执行do_nothing的函数。
释放2.1.2代码的memcpy处注释,运行程序,程序果然执行了do_nothing的函数
2.2、上述假如被踩的数据是其他值,程序就可能会直接崩溃。而当程序出现崩溃时,数据可能在崩溃前的某一时刻就被修改,出现崩溃的现场并不是第一现场,很难定位。如下面的代码:
2.3、可以在编译的时候添加-fstack-protector-all编译选项,减少定位难度(哪位大侠有更好的定位手段,在评论区求赐教),不至于代码跑飞,艰难查找到第一现场。
gcc stack.c -fstack-protector-all -o stack
没有添加-fstack-protector-all编译选项出现异常时的日志
此core_dump很难查找到问题原因,因为出现异常的地方不是第一现场。
2.4、栈区被踩问题的定位手段
栈区数据被飞踩问题定位手段_sydyh43的博客-CSDN博客
3、GOT表被修改情况
3.1、可以先看看下面的这篇分析
动态库*.so的延时绑定分析_sydyh43的博客-CSDN博客
打开git源码中的Makefile屏蔽和main函数的#if 0既可。
3.2、如以下的代码
3.3、这种内存被踩的情况一般不会出现,因为编译器默认会把relacation后的GOT表设置成只读。
4、综上所述,关于内存被踩的问题,需要编译的时候做好准备。在编译的时候添加编译选项,出现问题的时候可以保留第一现场。编译选项添加情况可以通过checksec.sh脚本校验,详见:
参考:(224条消息) 内存飞踩问题的几点思考_sydyh43的博客-CSDN博客
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2016-04-20 printk()函数的总结
2016-04-20 驱动程序调试方法之printk——自制proc文件(二)
2016-04-20 驱动程序调试方法之printk——自制proc文件(一)
2016-04-20 驱动程序调试方法之printk——printk的原理与直接使用
2014-04-20 VC添加背景图片 的一种方法