该类错误是修改了返回指针,一般是由于

1. 数组越界赋值。(数组没有边界检查)int a[8]; a[8],a[9],a[-1]。。都能正常编译,连接,运行时可能出错。

2.使用 strcpy等不安全(不带长度检测的函数),char a[1], char *b="aaa"; strcpy(a,b);

局部变量(函数内的变量)存在栈中,应为栈是先下(低地址)生长的,故 函数返回指针 要比局部变量的地址高,像类似的a[8]之类的就有机会访问到 函数返回指针了。

首先运行第一个程序:

#include “string.h”
void fun1(const char *str)
{
   char buffer[5];
  strcpy((char*)buffer, (char*)str);
}
int main()
{
   fun1(”AAAAAAAAAAAAAAAAAAAAAAAAA”);
}

程序执行结果是“段错误”。用GDB调试,在从fun1函数返回时出现“Cannot access memory at address 0×41414145”的错误提示,这大致符合期望。但有一点搞不明白的是被改写的返回地址是’AAAA’,即应该是0×41414141才对,实际情况 怎么会多了4个字节 (0×41414145)?

这个程序是由于返回地址无效导致错误,那么我就写一个有效的地址上去吧。运行第二个程序:

void fun1()
{
   int i;
   const char buffer[] = “111111111″;
   for (i = 0; i < 20; i++)
     *((int*)(buffer+i)) = (int)buffer;
}
int main()
{
   fun1();
}

程序的返回地址被改写成“有效”的地址“buffer”,只是内容确实无效的指令“11111111”,结果程序的运行结果是:

*** stack smashing detected ***: ./a.out terminated

GCC的缓冲区溢出保护

通过查阅资料知道,GCC有一种针对缓冲区溢出的保护机制,可通过选项“-fno-stack-protector”来将其关闭。实验中出现的错误信息,就正好是检测到缓冲区溢出而导致的错误信息。见出错程序的汇编代码:

<fun1>:
push   %ebp
mov    %esp,%ebp
sub    $0×28,%esp
mov    %gs:0×14,%eax
mov    %eax,-0×4(%ebp)        ; 把%gs:0×14保存到-0×4(%ebp) 中 
xor    %eax,%eax
movl   $0×31313131,-0xe(%ebp)
movl   $0×31313131,-0xa(%ebp)
movw   $0×31,-0×6(%ebp)
movl   $0×0,-0×14(%ebp)
jmp    8048423 <fun1+0×3f>
lea    -0xe(%ebp),%edx
mov    -0×14(%ebp),%eax
add    %eax,%edx
lea    -0xe(%ebp),%eax
mov    %eax,(%edx)
addl   $0×1,-0×14(%ebp)
cmpl   $0×13,-0×14(%ebp)
jle    8048412 <fun1+0×2e>
mov    -0×4(%ebp),%eax
xor    %gs:0×14,%eax        ; 检查%gs:0×14与-0×4(%ebp)的值是否相同 
je     804843a <fun1+0×56>        ; 如果相同则退出函数
call   804831c <__stack_chk_fail@plt>        ; 检测到缓冲区溢出,跳转到__stack_chk_fail@plt函数
leave
ret
<main>:
lea    0×4(%esp),%ecx
and    $0xfffffff0,%esp
pushl  -0×4(%ecx)
push   %ebp
mov    %esp,%ebp
push   %ecx
sub    $0×4,%esp        ; 在栈上分配4字节空间。在进入函数之后,其地址相当于-0×4(%ebp) 
add    $0×4,%esp
pop    %ecx
pop    %ebp
lea    -0×4(%ecx),%esp

从汇编代码看出,func2比func1只是多出了一条指令来为临时变量申请存储空间,这与其C代码相吻合;func3比func2却多出了一大片 代码,而其C代码的不同却只是临时数组的类型的不同而已。通过分析可知,这些多出的代码就是用来检查缓冲区溢出的。在调用函数之前,在栈上分配4字节的存 储空间。在进入函数之后,一个数(%gs:0×14)保存到这4字节空间中。在退出函数之前做一次检查,如果刚才保存的数被修改,那可以肯定是发生了缓冲 区溢出。

GS是附加段寄存器,我也没搞明白是干什么用的,更加不清楚%gs:0×14的值什么时候被确定。这种检测方法的思路很简单,就是在栈上放置一个随 机数,然后检查这个随机数有没有被改写。由于随机数放置在返回地址之前,聪明的黑客应该可以通过图3的方式植入恶意代码。但对黑客来说,这样有两个不便: (1)恶意代码需植入到当前函数的栈帧上,空间很小,很难植入攻击性强的代码;(2)由于主要是利用字符串拷贝来植入恶意恶意代码,而字符串拷贝是遇到 ’/0′才结束的,这样就要求恶意代码起始地址的低8位必须为全0,这样才可以刚好改写返回地址,而不会进入“雷区”(随机数)。在狭小的空间内,完成这 样的操作实在难于登天;如果可用空间很大的话,这两个问题其实也不难克服。

图3. 缓冲区溢出攻击

关于CPU和操作系统

我一直有个疑问:程序代码加载在代码段上,程序数据保存在数据段与堆栈段上,本来是河水不犯井水。缓冲区溢出只发生在数据段与堆栈段,只要规定这两 个段的内容可读写但不可执行,不就不需要担心缓冲区溢出攻击了吗?但事实上,许多程序为了提高效率,会在堆栈段上动态地生成可执行代码,比如Linux本 身就这样做,所以“数据段和堆栈段不可执行”这样的说法是错的。

Intel和AMD已经在一些CPU上加入了“防病毒”功能,这种CPU可区分哪些地址空间可以执行代码、而哪些地址空间不可以执行。

小结

通过实验,知道GCC有一定的保护机制,可防止缓冲区溢出攻击的发生。但这种方法有一定的局限性,所以仍有攻击的可能。我汇编很懒,有很多问题没有 完全搞明白。由于我很懒也没有毅力(我很痛恨自己的这种作风),不明白的地方留待“以后”研究。至于用Firefox浏览网页究竟会不会中毒的问题,应该 也还是会吧?

文章摘自:http://fujinbing.iteye.com/blog/1866682

*** stack smashing detected ***: ./server terminated的更多相关文章

  1. (转)Linux 下栈溢出问题分析解决 *** stack smashing detected *** XXXX terminated

    Linux 下栈溢出问题分析解决 *** stack smashing detected *** XXXX terminated 1.利用gdb 或者valgrind 定位到具体的代码 最近在Linu ...

  2. stack smashing detected解决过程

    在执行程序结束return 0 之后出现上图问题.主要原因是在程序中存在数组越界. 解决方法: 1. 查看定义的结构体内buffer大小,为4096字节 typedef struct { UINT32 ...

  3. stack smashing detect错误修正

    运行./a.out程序时候出现如下: *** stack smashing detected ***: ./a.out terminated段错误 (核心已转储) 一般这个错误是由于堆栈错误,很可能是 ...

  4. ubuntu 14.04 ns2.35 ***buffer overflow detected **: ns terminated解决办法

    1.按照如下教程安装 Install With Me !: How to Install NS-2.35 in Ubuntu-13.10 / 14.04 (in 4 easy steps) 2.运行一 ...

  5. **stack smashing detecting**

    stack smashing aborted 堆 猛烈撞击 流失 我在使用数据时写了 tmp_row = row + pos[num1][[0]; tmp_col = col + pos[num1][ ...

  6. not syncing : corrupted stack end detected inside scheduler

    自己在测试安装UBuntu的时候遇见了这个错误,not syncing : corrupted stack end detected inside scheduler解决办法 原因是低版本的VMwar ...

  7. vmware安装ubuntu ,一直处于end kernel panic - not syncing : corrupted stack end detected inside scheduler

    vmware安装ubuntu ,一直处于end kernel panic - not syncing : corrupted stack end detected inside scheduler y ...

  8. Cocos2d-x stack corruption detected: aborted

    adb logcat错误 :堆栈错误,,或者访问过界...通常不太好调试:: 但是以下两种情况最最常见: 1. ]; strcpy(aa,"abcdefghijk123457890" ...

  9. IAR调试cc2541串口遇到的Warning : Possible IDATA stack overflow detected

    1. 遇到的错误如下,似乎是栈空间不够使用 2. 修改界面如下,增加IDATA的大小,不过最大似乎是0XFF.

随机推荐

  1. Arcpy里莫名其妙的字段类型(Field type)

    对比6个常用的字段数据类型在Arcpy字段创建与字段属性输出时奇怪的事情: 添加字段使用arcpy.AddField_management: # addfield 的 type参数 # 浮点型,Flo ...

  2. 【学术篇】SPOJ GEN Text Generator AC自动机+矩阵快速幂

    还有5天省选才开始点字符串这棵技能树是不是太晚了点... ~题目の传送门~ AC自动机不想讲了QAQ.其实很久以前是学过然后打过板子的, 但也仅限于打过板子了~ 之前莫名其妙学了一个指针版的但是好像不 ...

  3. C# 进制转换(二进制、十六进制、十进制互转) 转载 https://www.cnblogs.com/icebutterfly/p/8884023.html

    C# 进制转换(二进制.十六进制.十进制互转)由于二进制数在C#中无法直接表示,所以所有二进制数都用一个字符串来表示例如: 二进制: 1010 表示为 字符串:"1010" int ...

  4. javascript基本类型及类型转换

    每种语言都有自己的基本类型,javascript也不例外.在javascript中有五大基本类型,分别是number,string,boolean,null,undefined.其他不属于这五种基本类 ...

  5. SVG和canvas

    1.SVG实现的圆环旋转效果 参考:http://www.softwhy.com/article-6472-1.html 2.SVG中的图形可以通过  transform="matrix(0 ...

  6. [NOIP模拟16]题解

    A.Blue 出题人大概已经去为国家处理积压子弹了? 贪心,让每一只青蛙(我怂行吧)都尽量往远跳,能到达的最远的被踩了就跳次远的,以此类推.可以维护一个单调队列,表示每只青蛙的位置(开始都是0).然后 ...

  7. Django框架(十)—— 多表操作:一对一、一对多、多对多的增删改,基于对象/双下划线的跨表查询、聚合查询、分组查询、F查询与Q查询

    目录 多表操作:增删改,基于对象/双下划线的跨表查询.聚合查询.分组查询.F查询与Q查询 一.创建多表模型 二.一对多增删改表记录 1.一对多添加记录 2.一对多删除记录 3.一对多修改记录 三.一对 ...

  8. Spring Boot主要目标

    Spring Boot主要目标 Spring Boot的主要目标是: 为所有Spring开发提供一个基本的,更快,更广泛的入门体验. 开箱即用,但随着需求开始偏离默认值,快速启动. 提供大型项目(例如 ...

  9. CUDA编程入门笔记

    1.线程块(block)是独立执行的,在执行的过程中线程块之间互不干扰,因此它们的执行顺序是随机的 2.同一线程块中的线程可以通过访问共享内存(shared memory)或者通过同步函数__sync ...

  10. MySql 主从复制及深入了解

    分享一个不错的mysql文章 https://segmentfault.com/a/1190000008942618