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)永远指向栈的顶端。
数组非法访问导致内存破坏
错误地操作数组导致的典型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文件的地址字符串,如‘E:\Top50.xlsx’, excel文件的第一行为表头,包含4列:股票交易代码(SZ000001&#x…

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

sgdisk 磁盘操作命令
划分磁盘分区 sgdisk -n 1:2G:50G /dev/sda 划分磁盘分区,一号分区划分为50G,同时预留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作为日常用语,配置好emacs的开发环境,有效提高日后的开发效率。 几篇老外的文章作为参考: Configing emacs as a python ide python、emacs 安装python和emacs就不用说了,这是必须的,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文件代码;void delay (){int i;for (i 0; i < 100000; i);}int xxxx (void){volatile unsi…

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

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

软件测试面试的linux基础知识,linux基础面试题
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼linux的用户管理useradd 用户名,添加用户【案例】useradd xiaomingpasswd 用户名,为新用户设密码【案例】passwd xiaoming,修改小明的密码userdel 用户名,删除用户【案例】userdel xi…

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

变体类的使用 package record case【转载】
**************理论区 start********************* DELPHI中记录的存储方式 在DELPHI中,我们用record关键字来表明一个记录,有时候,我们还会看到用packed record来声明的记录,这二者的区别就在于存储方式的不同;在wind…

【Boost】系列01:时间与日期
timer库(含timer,progress_timer和progress_display三个组件)和date_time timer用法: #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文件 解压: 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通讯开发-服务器连接 中我们成功连接到服务器上面,然后进入到主界面,接下来就是获取好友列表,这里我们分段开发,首先就是界面的设计,这里仿照QQ好友界面,里面的数据先是用模拟的,下一章获…

linux test数字txt,Linux26期 7月4日预习笔记
9.4/9.5 sed一,打印某行sed命令的格式为:sed -n np filename ,单引号内的n是一个数字,可以使用命令sed -n 1,$p filename ,如下去掉-n是有差异要想把所有行打印出来,可以使用命令sed -n 1,$p filename#sed -n 1,$p 文件名另外&…

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

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

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

c语言中二进制用什么字母表示方法,看C语言编码转换--------负数的二进制表示方法...
今天在看C语言编码转换时,既然对负数的二进制表示有些遗忘,查了下网上的资料,他们说的是个P!误人子弟!和大家讨论了下,贴出来已备在此遗忘:假设有一个 int类型的数,值为5,…

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

solaris11学习必用工具及ISO
一、软件准备、配置及相关说明1)Oracle VM VirtualBox & Oracle VM VirtualBox Extension Pack http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html#vbox说明:VirtualBox是Oracle自己的东西,很多考试…

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

ceph-osd无法获取osd map导致osd down掉的解决办法
环境:ceph-12.2.1 3节点测试性能集群 60块osd 最近ceph集群中有两个osd在重启之后遇到如下问题,osd获取不到集群osdmap产生coredump: ceph version 12.2.1.06 (3e7492b9ada8bdc9a5cd0feafd42fbca27f9c38e) luminous (stable)1: (()0xa2bf21) [0x7fcd9162…

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

suse linux登录黑屏,SUSE Linux登录时黑屏解决办法
我采用的virtual pc虚拟机,安装redhat enterprise 4 linux,安装后出现花屏,通过GRUB的单用户模式下修改/etc/X11/xorg.con我采用的virtual pc虚拟机,安装RedHat enterprise 4 linux,安装后出现花屏,通过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 解题报告
题目链接:http://codeforces.com/problemset/problem/352/A 题目意思:给定一个只有0或5组成的序列,你要重新编排这个序列(当然你可以不取尽这些数字),使得这个序列尽可能地大,并且能被90除尽。 …