当前位置: 首页 > 编程日记 > 正文

linux中非法内存,Linux下数组非法访问导致内存破坏 —— 引发segmentation fault的原因...

2012-02-05 wcdj

1, 调试时必需的栈知识

2, 数组非法访问导致内存破坏

调试时必需的栈知识

栈(stack)是程序存放数据的内存区域之一,其特征是LIFO(Last In First Out, 后进先出)式数据结构,即后放进的数据最先备取出。向栈中存储数据的操作称为PUSH(压入),从栈中取出数据称为POP(弹出)。在保存动态分配的自动变量时要使用栈。此外在函数调用时,栈还用于传递函数参数,以及用于保存返回地址和返回值。

#include

#include

#include

#define MAX (1UL << 20)

typedef unsigned long long u64;

typedef unsigned int u32;

u32 max_addend = MAX;

u64 sum_till_MAX(u32 n)

{

u64 sum;

n++;

sum = n;

if (n < max_addend)

sum += sum_till_MAX(n);

return sum;

}

int main(int argc, char** argv)

{

u64 sum = 0;

if ((argc == 2) && isdigit(*(argv[1])))

max_addend = strtoul(argv[1], NULL, 0);

if (max_addend > MAX || max_addend == 0) {

fprintf(stderr, "Invalid number is specified\n");

return 1;

}

sum = sum_till_MAX(0);

printf("sum(0..%lu) = %llu\n", max_addend, sum);

return 0;

}

计算从0到10的总和:

$ gcc -o sum -g sum.c

$ ./sum 10

sum(0..10) = 55

函数调用和栈的关系 —— 函数调用前后栈的变化情况

栈上依次保存了传给函数的参数、调用者的返回地址、上层栈帧指针和函数内部使用的自动变量。此外,处理有些函数时还会用栈来临时保存寄存器。每个函数都独自拥有这些信息,称为栈帧(stack frame)。此时需要适当地设置表示栈帧起始地址的帧指针(FP)。此外,栈指针(SP)永远指向栈的顶端。

0818b9ca8b590ca3270a3433284dd417.png

数组非法访问导致内存破坏

错误地操作数组导致的典型bug之一就是缓冲区溢出,即向我们分配的内存空间之外写入数据。特别是,如果这类bug发生在栈上的缓冲区中,就可能引发安全漏洞,因此出现了许多预防措施和应对措施,如通过指定缓冲区大小来编写安全的函数、源代码检查工具、编译器在构建时的报警等。即便如此,这种bug仍时有发生。

下面通过一个简单的例子进行分析:

#include

#include

char szInfo[] = "Oops! here is a buffer overflow, wcdj";

void func()

{

char buf[5];

strcpy(buf, names);

}

int main()

{

func();

return 0;

}

编译:

gcc -Wall -g -o hack28 hack28.c

打开coredump:

ulimit -c unlimited

运行:

gerryyang@wcdj:~/test/HACK>./hack28

段错误 (coredumped)

gerryyang@wcdj:~/test/HACK> ls -rtl

总计 160K

-rw-r--r-- 1 gerryyang users    186 2012-02-05 14:17 hack28.c

-rwxr-xr-x 1 gerryyang users   7986 2012-02-05 14:17 hack28

-rw------- 1 gerryyang users 1474562012-02-05 14:17 core

下面对程序进行调试:

gerryyang@wcdj:~/test/HACK> gdb hack28 core

GNU gdb 6.6

Copyright (C) 2006 Free SoftwareFoundation, Inc.

GDB is free software, covered by the GNUGeneral Public License, and you are

welcome to change it and/or distributecopies of it under certain conditions.

Type "show copying" to see theconditions.

There is absolutely no warranty forGDB.  Type "show warranty" fordetails.

This GDB was configured as"i586-suse-linux"...

Using host libthread_db library"/lib/libthread_db.so.1".

warning: Can't read pathname for load map:Input/output error.

Reading symbols from /lib/libc.so.6...done.

Loaded symbols for /lib/libc.so.6

Reading symbols from/lib/ld-linux.so.2...done.

Loaded symbols for /lib/ld-linux.so.2

Core was generated by `./hack28'.

Program terminated with signal 11,Segmentation fault.

#0 0x73692065 in ?? ()

(gdb) bt

#0 0x73692065 in ?? ()

#1 0x62206120 in ?? ()

#2 0x65666675 in ?? ()

#3 0x766f2072 in ?? ()

#4 0x6c667265 in ?? ()

#5 0x202c776f in ?? ()

#6 0x6a646377 in ?? ()

#7 0xbfb48600 in ?? ()

#8 0xb7e5a89c in __libc_start_main () from /lib/libc.so.6

Backtrace stopped: previous frame inner tothis frame (corrupt stack?)

(gdb)x/i 0x73692065

0x73692065:     Cannot access memory at address 0x73692065

(gdb)x/i 0x62206120

0x62206120:    Cannot access memory at address0x62206120

(gdb)

backtrace无法正确显示,在这种情况下backtrace是不可靠的。因为backtrace显示的内容很可能不是实际跟踪的内容。即代码突然跳转到或者调用了错误的地址 0x73692065,导致了segmentation fault的发生。

注意:栈帧#0、#1显示的地址上很难放置程序、共享内存等。大多数i386架构的Linux发行版中,程序被定位到0x08000000地址附近,共享库被定位到0xb0000000之后的地址。因此,记住在调试对象的环境中,标准情况下程序和共享库会被定位到什么地址,在阅读backtrace时就会很方便。

(gdb) x/30c $sp

0xbfb48660:     32 ' ' 97 'a'  32 ' '  98 'b' 117 'u' 102 'f' 102 'f' 101 'e'

0xbfb48668:     114 'r' 32 ' '  111 'o' 118 'v' 101 'e' 114 'r' 102 'f' 108'l'

0xbfb48670:     111 'o' 119 'w' 44 ','  32 ' ' 119 'w' 99 'c'  100 'd' 106 'j'

0xbfb48678:     0 '\0' -122 '\206'     -76 '´' -65 '¿' -100 '\234'     -88 '¨'

(gdb) x/30c $sp-15

0xbfb48651:     31 '\037'       -8 'ø' 79 'O'  111 'o' 112 'p' 115 's' 33'!'  32 ' '

0xbfb48659:     104 'h' 101 'e' 114 'r'101 'e' 32 ' '  105 'i' 115's'32 ' '

0xbfb48661:     97 'a' 32 ' '  98 'b'  117 'u' 102 'f' 102 'f' 101 'e' 114 'r'

0xbfb48669:     32 ' ' 111 'o' 118 'v' 101 'e' 114 'r' 102 'f'

(gdb)p(char*)$sp-15

$1 = 0xbfb48651 "\037øOops! here is abuffer overflow, wcdj"

(gdb) x/30w $sp-15

0xbfb48651:     0x6f4ff81f      0x20217370      0x65726568      0x20736920

0xbfb48661:     0x75622061      0x72656666      0x65766f20      0x6f6c6672

0xbfb48671:     0x77202c77      0x006a6463      0x9cbfb486      0x01b7e5a8

0xbfb48681:     0x04000000      0x0cbfb487      0x3dbfb487      0x00b7f9cc

0xbfb48691:     0x90000000      0x01b7f8f6      0x01000000      0xf4000000

0xbfb486a1:     0xc0b7f81f      0x00b7fabc      0xd8000000      0x80bfb486

0xbfb486b1:     0x6140be86      0x0048efa8      0x00000000      0x00000000

0xbfb486c1:     0x70000000      0xcdb7fa20

寻找错误地写入0x73692065这个数据的地方。很重要的是需要怀疑数据是否为字符串的一部分,因为错误地将数据写入地址的典型情况之一就是字符串复制。由于字符串的输入长度很难预测,若缓冲区过小,再加上对输入字符串的长度检查不完善,就可能发生这种状况。考虑到i386架构为littleendian,因此怀疑是“...eis...”这个字符串的一部分被写入了。然后此假设进行验证。首先栈指针指向的空间前后几乎都是字符串,因此将这种字符串写入栈上的错误位置的可能性很高,而且通过代码发现buf只有5字节长,复制的字符串超过了这个长度,从而导致缓冲区溢出。

通过以上分析,错误的原因就是,strcpy()写入字符串的空间,原本是用于保存返回main()地址的空间,所以func()结束之后返回main()时,就把“...e is...”对应的0x73692065数值当做了函数的返回地址,从而导致segmentation fault。

本例中的地址是字符串的一部分,比较容易判断,而只是将数值错误地写入的情况会更难调查。即便如此,如果那个数值经常在程序中出现,就可以将调查范围缩小到使用该数值的部分。

有时确定在哪里写入的错误数值不好确定,还可以借用objdump工具。

gerryyang@wcdj:~/test/HACK> objdump -shack28

hack28:   文件格式 elf32-i386

.interp 节的内容:

8048154 2f6c6962 2f6c642d 6c696e75782e736f  /lib/ld-linux.so

8048164 2e3200

......

.got.plt 节的内容:

8049644 78950408 00000000 0000000006830408  x...............

8049654 16830408 26830408                    ....&...

.data 节的内容:

8049660 00000000 00000000 70950408 00000000  ........p.......

8049670 00000000 00000000 0000000000000000  ................

8049680 4f6f7073 21206865 72652069 73206120  Oops! here is a

8049690 62756666 6572206f 766572666c6f772c  buffer overflow,

80496a0 20776364 6a000000                     wcdj...

.comment 节的内容:

......

总结

确定内存内容被破坏的过程可以按照某种步骤进行,但找到引发破坏的地方就必须依靠一定的感觉和经验。

参考:Debug Hacks

相关文章:

基于Matlab和Wind SQL数据库的通用选股策略回测程序

function [y,varargout]backtestcomplex(x,varargin) % Created on 2012-07-15 % latest justified on 2012-09-20 % 输入x是一个excel文件的地址字符串&#xff0c;如‘E:\Top50.xlsx’, excel文件的第一行为表头&#xff0c;包含4列&#xff1a;股票交易代码(SZ000001&#x…

Bzoj1123 Blockade

题目链接&#xff1a;https://loj.ac/problem/10104 日常水题&#xff0c;题目中已经给出了算法&#xff0c;写个模板即可&#xff0c;不会割点的这里有一篇博客&#xff1a;https://www.cnblogs.com/WWHHTT/p/9745499.html 难点是每个对可以互换顺序&#xff0c;然后删掉一个点…

sgdisk 磁盘操作命令

划分磁盘分区 sgdisk -n 1:2G:50G /dev/sda 划分磁盘分区&#xff0c;一号分区划分为50G&#xff0c;同时预留2G的空间 磁盘格式化 sgdisk -z -og /dev/sda 查看分区详情 sgdisk -i 1 /dev/hda查看hda第一分区的详情信息 [rootnode3 ~]# sgdisk -i 1 /dev/sdb Partition G…

spring.factories文件的作用

即spring.factories文件是帮助spring-boot项目包以外的bean(即在pom文件中添加依赖中的bean)注册到spring-boot项目的spring容器中。在Spring Boot启动时,它会扫描classpath下所有的spring.factories文件,加载其中的自动配置类,并将它们注入到Spring ApplicationContext中,使得项目能够自动运行。spring.factories文件是Spring Boot自动配置的核心文件之一,它的作用是。

Spring事务七大传播机制与五个隔离级别,嵌套事务

如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,反之,内层事务并不影响外层事务。当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。

emacs python环境配置

python作为日常用语&#xff0c;配置好emacs的开发环境&#xff0c;有效提高日后的开发效率。 几篇老外的文章作为参考&#xff1a; Configing emacs as a python ide python、emacs 安装python和emacs就不用说了&#xff0c;这是必须的&#xff0c;apt-get安装即可 基础python…

编写linux下跑马灯应用程序,01 arm11 led 跑马灯程序

.text.globl _start_start:ldr r0, 0x70000000orr r0, r0, #0x13mcr p15, 0, r0, c15, c2, 4ldr r0, 0x7e004000mov r1, #0str r1, [r0]ldr sp, 8*1024bl xxxxb .start.S文件代码&#xff1b;void delay (){int i;for (i 0; i < 100000; i);}int xxxx (void){volatile unsi…

Exchange 2013防止数据丢失DLP预览

介绍 防止数据丢失&#xff08;Data loss Prevention&#xff09;是Exchange Server 2013带来的一个新功能&#xff0c;感觉其实应该叫做防止数据泄露&#xff0c;许多第三方工具和设备也有类似的功能&#xff0c;而在Exchange 2013种已经直接集成了&#xff0c;并且之前的传输…

Django 模型层(1)

知识预览 ORM简介单表操作章节作业回到顶部ORM简介 MVC或者MVC框架中包括一个重要的部分&#xff0c;就是ORM&#xff0c;它实现了数据模型与数据库的解耦&#xff0c;即数据模型的设计不需要依赖于特定的数据库&#xff0c;通过简单的配置就可以轻松更换数据库&#xff0c;这极…

软件测试面试的linux基础知识,linux基础面试题

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼linux的用户管理useradd 用户名&#xff0c;添加用户【案例】useradd xiaomingpasswd 用户名&#xff0c;为新用户设密码【案例】passwd xiaoming&#xff0c;修改小明的密码userdel 用户名&#xff0c;删除用户【案例】userdel xi…

s-sort命令

对文本操作进行排序&#xff0c;以行为单位&#xff0c;依次根据ascii值进行比较&#xff0c;默认的排序方式为升序 sort [-bcfMnrtk][源文件][-o 输出文件]补充说明&#xff1a;sort可针对文本文件的内容&#xff0c;以行为单位来排序。 参 数&#xff1a;-b 忽略…

变体类的使用 package record case【转载】

**************理论区 start********************* DELPHI中记录的存储方式 在DELPHI中&#xff0c;我们用record关键字来表明一个记录&#xff0c;有时候&#xff0c;我们还会看到用packed record来声明的记录&#xff0c;这二者的区别就在于存储方式的不同&#xff1b;在wind…

【Boost】系列01:时间与日期

timer库(含timer,progress_timer和progress_display三个组件)和date_time timer用法&#xff1a; #include <boost/timer.hpp> #include <iostream> using namespace std; using namespace boost;int main() {timer t;//开始计时cout<<"max timespan:&q…

git学习网址

1、git 上传代码到GitHub 以及git删除github上文件和文件的命令 - lexsaints - CSDN博客 https://blog.csdn.net/weixin_42350212/article/details/80560272 2、git误区error: failed to push some refs to gitgithub.com: - whaleluo的博客 - CSDN博客 https://blog.csdn.n…

Linux压缩和解压缩命令集

.tar文件 解压tar zxvf FileName.tar打包tar czvf SourceName.tar DirName .gz文件 解压&#xff1a; gunzip FileName.gzgzip -d FileName.gz 压缩 gzip FileName .tar.gz 和.gz文件 解压tar zxvf FileName.tar.gz压缩tar zcvf FileName.tar.gz DirName .bz2文件 解压…

XMPP通讯开发-好友获取界面设计

在XMPP通讯开发-服务器连接 中我们成功连接到服务器上面&#xff0c;然后进入到主界面&#xff0c;接下来就是获取好友列表&#xff0c;这里我们分段开发&#xff0c;首先就是界面的设计&#xff0c;这里仿照QQ好友界面&#xff0c;里面的数据先是用模拟的&#xff0c;下一章获…

linux test数字txt,Linux26期 7月4日预习笔记

9.4/9.5 sed一&#xff0c;打印某行sed命令的格式为&#xff1a;sed -n np filename ,单引号内的n是一个数字&#xff0c;可以使用命令sed -n 1,$p filename ,如下去掉-n是有差异要想把所有行打印出来&#xff0c;可以使用命令sed -n 1,$p filename#sed -n 1,$p 文件名另外&…

提高PHP运行速度的小技巧

使用PHP的最大1个优势就是速度快。一般情况下&#xff0c;PHP总是具有足够的速度支持Web内容动态生成&#xff0c;许多时候甚至无法找出比它更快的方法。然而&#xff0c;当面对庞大的访问量、高负荷的应用、有限的带宽&#xff0c;以及其他各种带来性能瓶颈的因素时&#xff0…

基于Python, Selenium, Phantomjs无头浏览器访问页面

引言&#xff1a; 在自动化测试以及爬虫领域&#xff0c;无头浏览器的应用场景非常广泛&#xff0c;本文将梳理其中的若干概念和思路&#xff0c;并基于代码示例其中的若干使用技巧。 1. 无头浏览器 通常大家在在打开网页的工具就是浏览器&#xff0c;通过界面上输入网址就可以…

groovy–流程控制

在本篇文章中&#xff0c;我们将介绍逻辑分支&#xff0c;循环&#xff0c;以及如何从if-else以及try-catch代码块中返回值。 if – elseGroovy 支持Java传统的if-else语法&#xff1a; def x false def y falseif ( !x ) {x true }assert x trueif ( x ) {x false } else…

c语言中二进制用什么字母表示方法,看C语言编码转换--------负数的二进制表示方法...

今天在看C语言编码转换时&#xff0c;既然对负数的二进制表示有些遗忘&#xff0c;查了下网上的资料&#xff0c;他们说的是个P&#xff01;误人子弟&#xff01;和大家讨论了下&#xff0c;贴出来已备在此遗忘&#xff1a;假设有一个 int类型的数&#xff0c;值为5&#xff0c…

du和df的区别

du,disk usage 是通过搜索文件来计算每个文件的大小然后累加&#xff0c;du能看到的文件只是一些当前存在 的&#xff0c;没有被删除的。他计算的大小就是当前他认为存在的所有文件大小的累加和df,disk free,通过文件系统来快速获取空间大小的信息&#xff0c;当我们删除一个文…

solaris11学习必用工具及ISO

一、软件准备、配置及相关说明1&#xff09;Oracle VM VirtualBox & Oracle VM VirtualBox Extension Pack  http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html#vbox说明&#xff1a;VirtualBox是Oracle自己的东西&#xff0c;很多考试…

谜题59:什么是差?

下面的程序在计算一个int数组中的元素两两之间的差&#xff0c;将这些差置于一个集合中&#xff0c;然后打印该集合的尺寸大小。那么&#xff0c;这个程序将打印出什么呢&#xff1f; import java.util.*;public class Differences {public static void main(String[ ] args) {…

ceph-osd无法获取osd map导致osd down掉的解决办法

环境&#xff1a;ceph-12.2.1 3节点测试性能集群 60块osd 最近ceph集群中有两个osd在重启之后遇到如下问题,osd获取不到集群osdmap产生coredump&#xff1a; ceph version 12.2.1.06 (3e7492b9ada8bdc9a5cd0feafd42fbca27f9c38e) luminous (stable)1: (()0xa2bf21) [0x7fcd9162…

读书笔记2013第13本:《怎样解题》

《怎样解题》这本书是在看《编程大师访谈录》&#xff08;中文版第12页&#xff09;这本书时无意发现的&#xff0c;一个编程大师推荐这本书来指导编程设计&#xff0c;google到这本书后粗略地翻看了一遍&#xff0c;发现是一本教学生如何解数学题的非常有年头的书。随着仔细品…

suse linux登录黑屏,SUSE Linux登录时黑屏解决办法

我采用的virtual pc虚拟机&#xff0c;安装redhat enterprise 4 linux&#xff0c;安装后出现花屏&#xff0c;通过GRUB的单用户模式下修改/etc/X11/xorg.con我采用的virtual pc虚拟机&#xff0c;安装RedHat enterprise 4 linux&#xff0c;安装后出现花屏&#xff0c;通过GRU…

应用构建工具包 Ecere SDK

Ecere SDK是一个跨平台的工具包构建软件应用程序。目前运行在Windows、Linux和Mac OS X(通过X11)。通过 Ecere SDK,可以开发一次应用程序,并将其部署在所有支持的平台上与一个轻量级运行时环境。它引入了eC这个面向对象语言来源于和完全兼容C,性能好也易于使用。一个内置的3d引…

第39-43课 thinkphp5完成商品会员价格功能(后置勾子afterInsert)

目录 功能一:利用后置勾子,处理好商品主键id,会员的价格,再插入member_price表里.要实现的功能:思路:html里控制器里模型里的后置勾子afterInsert()功能二:利用后置勾子,上传图片,批量生成缩略图,再插入goods_photo表里.要实现的功能:控制器里的用调用模型用save()方法保存模型…

codeforces A. Jeff and Digits 解题报告

题目链接&#xff1a;http://codeforces.com/problemset/problem/352/A 题目意思&#xff1a;给定一个只有0或5组成的序列&#xff0c;你要重新编排这个序列&#xff08;当然你可以不取尽这些数字&#xff09;&#xff0c;使得这个序列尽可能地大&#xff0c;并且能被90除尽。 …