首页 > 系统相关 >内存飞踩问题的几点思考

内存飞踩问题的几点思考

时间:2023-04-20 10:02:55浏览次数:47  
标签:栈区 do return int 内存 思考 nothing 几点 0x%

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, #4   10498: e24dd010 sub sp, sp, #16 ;确定好栈区大小   1049c: e50b0010 str r0, [fp, #-16]   104a0: e50b1014 str r1, [fp, #-20] ; 0xffffffec   104a4: 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, #4   10498: e24dd018 sub sp, sp, #24 ;栈区空间增大   1049c: e50b0018 str r0, [fp, #-24] ; 0xffffffe8   104a0: e50b101c str r1, [fp, #-28] ; 0xffffffe4   104a4: 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程序的常用保护机制 | 上善若水

 

参考:(224条消息) 内存飞踩问题的几点思考_sydyh43的博客-CSDN博客

 

 

标签:栈区,do,return,int,内存,思考,nothing,几点,0x%
From: https://www.cnblogs.com/lidabo/p/17335723.html

相关文章

  • 一文掌握C/C++内存泄漏,防止内存泄漏以及检测工具!
    在写C/C++代码的时候,经常需要为程序分配动态内存,难免就会发生内存泄漏的情况,本文就来说一下如何防止C/C++内存泄漏!在说防止内存泄漏前,先说一下什么是内存泄漏。一、什么是内存泄漏?通俗一点说就是,程序中动态分配的内存并没有正确的释放。内存泄漏(Memoryleak)是在计算机科学......
  • 内存问题难定位,那是因为你没用ASAN
    ASAN全称:AddressSanitizer,google发明的一种内存地址错误检查器。目前已经被集成到各大编译器中。本文分享自华为云社区《内存定位利器-ASAN使用小结》,作者:云存储开发者支持团队。1.什么是ASANASAN全称:AddressSanitizer,google发明的一种内存地址错误检查器。目前已经被集......
  • 使用mprotect定位踩内存故障
    前言对于C语言来说,内存被踩是比较常见的问题,轻则普通变量被改写程序逻辑出错,重则指针变量被改写引发指针解引用出现未定义行为风险;定位内存被踩一直是棘手的难题,如果出现程序跑死,一般可以通过堆栈信息来定位:1)查看跑死的调用链,确定跑死代码的位置;2)根据pc指针找到具体代码;3)走......
  • GE反射内存实时通讯网络解决方案
    时通讯网络是用于需要较高实时性要求的应用领域的专用网络通讯技术,一般采用基于高速网络的共享存储器技术实现。它除了具有严格的传输确定性和可预测性外,还具有速度高、通信协议简单、宿主机负载轻、软硬件平台适应性强、可靠的传输纠错能力、支持中断信号的传输等特点。本方案选......
  • Linux内存管理之mem_map对象.md
    在linux内核中,所有的物理内存都用structpage结构来描述,这些对象以数组形式存放,而这个数组的地址就是mem_map。内核以节点node为单位,每个node下的物理内存统一管理,也就是说在表示内存node的描述类型structpglist_data中,有node_mem_map这个成员,其针对平坦型内存进行描述(CONFIG_FL......
  • CANN开发实践:4个DVPP内存问题的典型案例解读
    摘要:由于DVPP媒体数据处理功能对存放输入、输出数据的内存有更高的要求(例如,内存首地址128字节对齐),因此需调用专用的内存申请接口,那么本期就分享几个关于DVPP内存问题的典型案例,并给出原因分析及解决方法。本文分享自华为云社区《FAQ_DVPP内存问题案例》,作者:昇腾CANN。DVPP是昇腾......
  • 实时查看Docker容器占用的CPU、内存状态
    安装Linux下安装方法:wgethttps://github.com/bcicen/ctop/releases/download/v0.5/ctop-0.5-linux-amd64-Octopsudomvctop/usr/local/bin/sudochmod+x/usr/local/bin/ctop执行命令:ctop使用ctop运行后,通过下面的按键可以实现不同的功能1)a-只查看运行状态的容器f-......
  • 在Go语言中,如何优化内存使用效率?
    在Go语言中,可以通过以下几种方式来优化内存使用效率:避免使用过多的内存尽可能地避免使用过多的内存是最有效的内存优化方法之一。在编写代码时,应该尽可能地避免使用全局变量和大量的临时变量。同时,可以使用常量、静态变量和缓存等方式来避免频繁地分配和释放内存。及时释放不......
  • 【valgrind】软件调试工具-valgrind内存调试工具
    valgrind工具安装Ubuntu环境安装sudoaptinstallvalgrind源码编译1.源码下载http://valgrind.org/downloads/valgrind-3.12.0.tar.bz22.valgrind编译安装tar-jxvfvalgrind-3.12.0.tar.bz2cdvalgrind-3.12.0./configuremakesudomakeinstallvalgrind运行分析程......
  • SQL Server占用内存不释放卡死问题
      最近项目中发现使用SQLServer的机器会出现10天左右占满内存卡死情况,百度后发现对应的原因如下:    即:SQLServer内存管理是分配了最大内存是多少,就会使用多少,在再次使用的时候,才会释放掉空闲的内存,它不会主动全部释放掉所有空闲内存。所以解决方式是:在sqlSe......