1、程序编译,链接后生成二进制可执行程序。二进制可执行文件以elf格式实现排列。可以通过readelf -S xxxx查看具体section的划分,粗略划分如下图所示。

在这些section中,代码段是只读的,自然也就不存在代码(指令)被改写的情况。数据段,堆,栈区具有读写的属性,但是数据段和堆一般存放的是数据,不涉及到指令的问题。剩下的栈区,存放的既有数据,又有代码(指令),可能存在代码(指令)被改写,即内存被飞踩现象。

2、栈空间数据被修改情况

2.1、先做个实验(ARM 32环境)

2.1.1、栈区空间

#include <unistd.h>
#include <stdio.h>int do_nothing(int a)
{return a;
}int max(int a,int b)
{int c = 0;do_nothing(c);return a + b;
}int main()
{int res = 0;int a = 1;int b = 2;res = max(a, b);return res;
}
arm-linux-gcc func.c -o func
arm-linux-objdump -d func > func.txt

查看反汇编结果

00010490 <max>:10490:  e92d4800    push    {fp, lr}         ;把bl <max>的下一条指令地址lr保存到栈区10494:  e28db004    add fp, sp, #410498:    e24dd010    sub sp, sp, #16          ;确定好栈区大小1049c: e50b0010    str r0, [fp, #-16]104a0:    e50b1014    str r1, [fp, #-20]  ; 0xffffffec104a4:  e3a03000    mov r3, #0

增加max函数的局部变量个数,再查看相对应的反汇编

int max(int a,int b)
{int c = 0;int d = 0;int e = 0;c = d;do_nothing(c);return a + b;
}
00010490 <max>:10490:  e92d4800    push    {fp, lr}10494:  e28db004    add fp, sp, #410498:    e24dd018    sub sp, sp, #24     ;栈区空间增大1049c:   e50b0018    str r0, [fp, #-24]  ; 0xffffffe8104a0:  e50b101c    str r1, [fp, #-28]  ; 0xffffffe4104a4:  e3a03000    mov r3, #0

由此可见,栈区的大小在程序编译的时候就已经确定。存放着函数退出后下一条指令的地址和局部变量的数值。

2.1.2、栈区数据

#include <stdio.h>
#include <string.h>int do_nothing()
{printf("nothing\n");
}int func(int i)
{int a = 6;int b = 0;int *p = NULL;char num[3] = {0x6d, 0x04, 0x01};p = &b;printf("b addr=0x%x, func=0x%x\n", p, do_nothing);printf("stack value:0x%x, 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", *(p + 1), *(p + 2), *(p + 3), *(p + 4), *(p + 5), *(p + 6), *(p + 7), *(p + 8));
//  memcpy((char *)(p+8), num, 3);return a * i;
}int main(void)
{int i = 1;func(i);i++;return i;
}

从局部变量中,获取栈区地址,打印栈区里面的部分数据。

第一个红框存放着局部变量的数据,第二个红框存放着退出函数后下一条指令的地址,可以从反汇编中确认。

2.1.3、修改栈区数据,其中存放的下一条指令的地址0x10545被改写,程序运行是不是就会出现异常。

上图截图中绿框所示,对应着是另外一个函数do_nothing的地址,假如把栈区0x10545的数据改写成do_nothing的地址,应该就会执行do_nothing的函数。

释放2.1.2代码的memcpy处注释,运行程序,程序果然执行了do_nothing的函数

2.2、上述假如被踩的数据是其他值,程序就可能会直接崩溃。而当程序出现崩溃时,数据可能在崩溃前的某一时刻就被修改,出现崩溃的现场并不是第一现场,很难定位。如下面的代码:

void fun(void) {char arr[5];strcpy(arr, "are you ok.are you ok.");return;
}

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、如以下的代码

int arr[2];        //arr数组是全局变量void fun(void) {arr[-8] = 0xFF;return;
}

3.3、这种内存被踩的情况一般不会出现,因为编译器默认会把relacation后的GOT表设置成只读。

4、综上所述,关于内存被踩的问题,需要编译的时候做好准备。在编译的时候添加编译选项,出现问题的时候可以保留第一现场。编译选项添加情况可以通过checksec.sh脚本校验,详见:

linux程序的常用保护机制 | 上善若水

内存飞踩问题的几点思考相关推荐

  1. 内存泄漏 内存溢出 踩内存 malloc底层实现原理

    本文主要对内存泄漏.内存溢出.内存踩踏[踩内存]以及malloc的底层实现原理进行了总结.话不多说,直接往下看: 参考文章: 内存泄漏与内存溢出: https://blog.csdn.net/ruir ...

  2. 关于iphone、QQ通讯录、飞聊联系人排序设计的思考

    目前,对于联系人的排序,如果不考虑对方的在线状态,一般都是按照音序排序的.所谓音序排序,也就是拼音字母的顺序:首先是按照整个拼音的首字母(26个字母从A~Z)的顺序排列,如果首字母相同,则依次按照声母 ...

  3. java构建内存池队列_内存池完整实现代码及一些思考

    为了提高效率和有效的监控内存的实时状态,我们采取了内存池的思想来解决效率与对内存实现监控的问题. 网上查找到了一些方案,根据自己的理解实现了应用. 我们什么时候要调用到内存池, 1,当我们频繁的申请释 ...

  4. C语言系统内存被踩情况总结

    C语言由于可以直接操作内存,给我们的编程带来了便利,同时也带来了内存写越界之类的问题,常常造成我们的系统crash.下面总结了我在工作中碰到的导致内存越界的各种场景,以供分析此类问题时作个参考. 1. ...

  5. 栈区数据被飞踩问题定位手段

    1.栈溢出或者栈数据被踩时,继续运行就会出现segmentation fault.可以尝试着接管SIGSEGV信号,在信号处理函数中保存一些出现异常时候的信息. 2.基于栈溢出场景,栈空间被破坏,也就 ...

  6. 简记H2 Database内存数据踩过的坑

    开发入门步骤: 一.maven中添加依赖项 <dependency><groupId>com.h2database</groupId><artifactId& ...

  7. linux踩内存怎么定位,问题定位:内存泄漏,踩内存。

    1.内存泄漏 确定现象: linux 内存泄漏,可以查看slabinfo 和另外一个proc下(貌似meminfo),关于内存的信息,可以看到内存是否在不断减少,以及减少的速度. vxworks系统, ...

  8. 使用mprotect定位踩内存故障

    前言 对于 C 语言来说,内存被踩是比较常见的问题,轻则普通变量被改写程序逻辑出错,重则指针变量被改写引发指针解引用出现未定义行为风险: 定位内存被踩一直是棘手的难题,如果出现程序跑死,一般可以通过堆 ...

  9. 全局变量同名导致踩内存

    今天遇到一个诡异的内存被踩的问题,后来发现是一个全局变量与另一个静态库中的全局变量重名了, a.c: #include <stdio.h>int g_ctx = 0; int g_over ...

最新文章

  1. linux 怎么删除大文件,如何在Linux中删除超大的(100-200GB)文件
  2. oracle pga的作用,浅析Oracle中PGA和UGA两者间的区别
  3. 因果关系和相关关系 大数据_数据科学中的相关性与因果关系
  4. 关于JFace中的向导式对话框(WizardDialog类)
  5. 小程序 图片上传php后台,微信小程序图片选择、上传到服务器、预览(PHP)实现实例...
  6. 谷歌终于拒绝 AI 武器化了!
  7. Jepack4.5.1上手动安装cuda10.0 cudnn 7, Jepack4.5.1 TX2 i安装pytorch1.6.0
  8. Spring学习(下)
  9. SPSS做因子分析(非常细致的过程)
  10. 【PS】抠图教程(0基础快速入门)
  11. 【概率论与数理统计】1.5 独立性
  12. Goldendict 及其词典详述
  13. 三星S5终于降临 4月上市开卖的新机盘点
  14. 华为云冰山安全,让用户安心用云
  15. 聚焦2019世界人工智能大会:看马斯克、马云“唇枪舌战”,谁更胜一筹?
  16. element filtername is not allowed here
  17. 基于SphereFace深度学习的人脸考勤系统(Caffe+windows+OpenCV)
  18. pusher 创建新应用_laravel之pusher应用广播事件- 黑白课堂
  19. Direct exchange
  20. Windows下利用Ghost32一次性完成U盘版PE的制作

热门文章

  1. 计算机教室展台,多媒体教室视频展示台的系统.ppt
  2. 《风尚坐火箭学习vue》-- 第二章:页面中输出hello Vue
  3. 淘宝API图片尺寸的缩略图解决办法
  4. clumsy一款模拟弱网的工具
  5. ping命令详解 ping命令入门详解
  6. indexof java_Java中indexOf的用法
  7. 三门峡大坝和小浪底水库,是不是相互依存的关系?
  8. androidAPP 接入微信/支付宝支付,获取应用的签名(随笔)
  9. Spark中mapToPair和flatMapToPair的区别【附示例源码及运行结果】
  10. 量子计算机作文材料,作文素材:九章问世,量子科技,你该知道的世界!.docx...