Stack smashing是堆栈缓冲区溢出(stack buffer overflow)的一个时髦称谓。它表示利用代码中存在的缓冲区溢出bug而发起的攻击。在早期,这完全是程序员的责任,他们要确保代码中不存在缓冲区溢出的问题。但是随着时间推移,技术的不断发展,现在像gcc这样的编译器已经有编译选项用来确保缓冲区溢出问题不被攻击者利用来破坏系统或者程序。

有一次当我试图重现一个缓冲区溢出的问题时我才了解到这些编译选项。我是在Ubuntu 12.04上进行试验的,gcc版本为4.6.3。我所做的很简单:

#include

#include

int main(void)

{

int len = 0;

char str[10] = {0};

printf("\n Enter the name \n");

gets(str); // Used gets() to cause buffer overflow

printf("\n len = [%d] \n", len);

len  = strlen(str);

printf("\n len of string entered is : [%d]\n", len);

return 0;

}

在上面的代码中,我故意使用gets()函数来接收字符串,之后计算字符串的长度,并输出到标准输出—默认是屏幕。这里的想法是输入超过10个长度的字符串,由于gets()函数并不检测数组边界,所以它将会把字符写入到10个以外的地址,这样就会发生缓冲区溢出。我运行程序之后的结果如下所示:

$ ./stacksmash

Enter the name

TheGeekStuff

len = [0]

len of string entered is : [12]

*** stack smashing detected ***: ./stacksmash terminated

======= Backtrace: =========

/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb76e4045]

/lib/i386-linux-gnu/libc.so.6(+0x103ffa)[0xb76e3ffa]

./stacksmash[0x8048548]

/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb75f94d3]

./stacksmash[0x8048401]

======= Memory map: ========

08048000-08049000 r-xp 00000000 08:06 528260    /home/himanshu/practice/stacksmash

08049000-0804a000 r--p 00000000 08:06 528260    /home/himanshu/practice/stacksmash

0804a000-0804b000 rw-p 00001000 08:06 528260    /home/himanshu/practice/stacksmash

0973a000-0975b000 rw-p 00000000 00:00 0          [heap]

b75af000-b75cb000 r-xp 00000000 08:06 787381    /lib/i386-linux-gnu/libgcc_s.so.1

b75cb000-b75cc000 r--p 0001b000 08:06 787381    /lib/i386-linux-gnu/libgcc_s.so.1

b75cc000-b75cd000 rw-p 0001c000 08:06 787381    /lib/i386-linux-gnu/libgcc_s.so.1

b75df000-b75e0000 rw-p 00000000 00:00 0

b75e0000-b7783000 r-xp 00000000 08:06 787152    /lib/i386-linux-gnu/libc-2.15.so

b7783000-b7784000 ---p 001a3000 08:06 787152    /lib/i386-linux-gnu/libc-2.15.so

b7784000-b7786000 r--p 001a3000 08:06 787152    /lib/i386-linux-gnu/libc-2.15.so

b7786000-b7787000 rw-p 001a5000 08:06 787152    /lib/i386-linux-gnu/libc-2.15.so

b7787000-b778a000 rw-p 00000000 00:00 0

b7799000-b779e000 rw-p 00000000 00:00 0

b779e000-b779f000 r-xp 00000000 00:00 0          [vdso]

b779f000-b77bf000 r-xp 00000000 08:06 794147    /lib/i386-linux-gnu/ld-2.15.so

b77bf000-b77c0000 r--p 0001f000 08:06 794147    /lib/i386-linux-gnu/ld-2.15.so

b77c0000-b77c1000 rw-p 00020000 08:06 794147    /lib/i386-linux-gnu/ld-2.15.so

bfaec000-bfb0d000 rw-p 00000000 00:00 0          [stack]

Aborted (core dumped)

令我惊讶的是,运行环境居然可以检测到缓冲区溢出的情况。你可以在输出信息上看到“检测到栈溢出”(stack smashing detected)的信息。这促使我去探索缓冲区溢出是如何被检测到的。

当我探索原因时,我发现了gcc的一个编译选项:-fstack-protector,以下是关于这个选项的描述:

-fstack-protector

启用该选项后编译器会产生额外的代码来检测缓冲区溢出,例如栈溢出攻击。这是通过在有缺陷的函数中添加一个保护变量来实现的。这包括会调用到alloca的函数,以及具有超过8个字节缓冲区的函数。当执行到这样的函数时,保护变量会得到初始化,而函数退出时会检测保护变量。如果检测失败,会输出一个错误信息并退出程序。

!注意:在Ubuntu 6.10以及之后的版本中,如果编译时没有指定-fno-fstack-protector, -nostdlib或者-ffreestanding选项的话,那么这个选项对于C,C++,ObjC,ObjC++语言默认是启用的。

所以,你会发现gcc已经使用插入附加代码的方式来检测缓冲区溢出的问题。我想到的下一个问题是,我从来没有在编译时加入这个编译选项,这个功能是怎样启用的?然后我读到最后两行,在Ubuntu6.10之后的版本上,此功能已经默认启用了。

下一步,我决定使用-fno-fstack-protector选项来取消这个栈溢出检测功能。我对同样的代码编译之后运行,使用和之前一样输入,下面是我的做法以及运行结果:

$ gcc -Wall -fno-stack-protector stacksmash.c -o stacksmash

$ ./stacksmash

Enter the name

TheGeekStuff

len = [26214]

len of string entered is : [12]

可以看到,一旦使用了这个编译选项(根据前面的编译选项说明,这里-fstack-protector是不会默认开启的),使用相同的输入,运行环境根本无法检测到缓冲区溢出的问题,len的值已经被破坏了。

当然,如果你对gcc很陌生,你也应该理解我们之前讨论过的最常用的gcc编译选项。

linux 编译条件检查,如何利用GCC编译选项检测栈溢出相关推荐

  1. linux编译动态库未定义,GCC链接库的一个坑:动态库存在却提示未定义动态库的函数...

    背景 在GCC中已经指定链接库,然而编译时却提示动态库函数未定义! 测试出现的错误提示如下: [GMPY@13:48 tmp]$gcc -o test -L. -lmylib test.c /tmp/ ...

  2. linux恶意代码检查软件,Yara:恶意软件检测神器

    yara是一款用于帮助软件研究人员检测恶意软件和代码的开源工具,可以分析各种文件以及正在运行的进程. Yara支持的系统平台 Yara工具自带了一个小型的搜索引擎,可以在window.linux.Ma ...

  3. linux下编译安装gcc,Linux编译安装GCC 5.1.0

    Linux下编写C/C++程序自然缺不了一个优秀的编译器,Linux下比较常见的自然是GCC了.2015年4月下旬GCC也出到了5.1.0版本,对于C++11/14也有了更好的支持了.因为最近在学习O ...

  4. Linux | 编译原理、gcc的命令参数、自动化构建工具 make/Makefile

    文章目录 编译原理 预处理 编译 汇编 链接 gcc的常用命令参数 make 和 Makefile 的概念 make的运行 通配符 自动化变量 伪目标.PHONE:[命令] 编译原理 在解释 make ...

  5. linux编译fdk aac,Ubuntu下利用NDK编译ffmpeg+x264+fdk-aac

    由于FFmpeg.x264.Fdk-aac的版本问题,所以编译的时候有很多坑 编译顺序: 首先利用脚本分别编译x264和fdk-aac库,生成头文件(.h)与静态库文件(.a/.la). 将FFmpe ...

  6. linux c 如何编译静态库,Linux C 编程入门之一:gcc 编译动态库和静态库

    主调用程序源代码3-1:main.c /** * main.c */ #include #include #include "hello_fn.h" int main () { h ...

  7. centos linux编译c,紧急提醒!Linux是如何编译C语言程序文件的?CentOS 8的gcc使用方法介绍...

    一句话告诉你gcc怎么编译C文件 执行命令 gcc Tristone.c  -o Tristone 解释:"Tristone.C"Tristone可执行文件编译,编译完成后&quo ...

  8. linux 编译-l,GCC编译器下的-L与-l的区别

    我们用gcc编译程序时,可能会用到"-I"(大写i),"-L"(大写l),"-l"(小写l)等参数,下面做个记录: 例: gcc -o he ...

  9. linux编译grpcswift,grpc使用记录(一)编译(mscv/gcc)

    目录 1.编译前的准备工作 1.下载源码 git clone https://github.com/grpc/grpc.git 2.下载依赖项,grpc的依赖项都以子模块的方式记录在third_par ...

  10. 【GCC】gcc警告选项汇总--编辑中|gcc编译选项

    目录 前言 请求或取消警告选项 GCC编译选项 参考原文:https://blog.csdn.net/qq_17308321/article/details/79979514 前言 警告:不是错误的, ...

最新文章

  1. 华御密盾智能防信息泄密系统
  2. JSTL标签的用法详解
  3. 超有用的,从此vi变得友好了
  4. 善于总结所做所学的内容
  5. 【Python CheckiO 题解】Date and Time Converter
  6. javascript excel
  7. ubuntu mysql 5.7_Ubuntu 16.04 上安装 MySQL 5.7 教程
  8. python 获取浏览器句柄下的网页控件_python webdriver操作浏览器句柄
  9. GridView中不能用If?
  10. 【演化学习】初识platEMO-MOEA/D、NSGA-Ⅱ-DTLZ、HV
  11. .net创建XML文件的两种方法
  12. Ubuntu 20编译安装GCC 7.3.0
  13. VTD-传感器使用小结
  14. powshell的tree命令
  15. 区块链技术从入门到精通教程
  16. 最小环flody hdu6080
  17. 孵出鸡蛋然后拿去卖钱
  18. 获取屏幕分辨率和刷新率
  19. Day 11 Contractions and Present Perfect
  20. 全球物料管理MMOG/LE体系培训资料(最新)

热门文章

  1. Rust: codewars的DNA to RNA Conversion
  2. 阿里云产品经理吴华剑:SLS 的产品功能与发展历程
  3. 阿里云 Link ID² 标准项目获浙江省标准创新重大贡献奖
  4. 计算机学院金海教授当选2019IEEE会士
  5. linux命令增删改查,hw_linux_study_day003,Linux系统终端中的增删改查命令
  6. 【元胞自动机】基于matlab保守策略元胞自动机三车道(不开放辅路,软件园影响)交通流模型【含Matlab源码 1294期】
  7. 【数学建模】基于matlab细胞传输模型实现交通流【含Matlab源码 376期】
  8. scala和java集合的区别_Scala中Array和List的区别
  9. heroku_如何通过5个步骤在Heroku上部署机器学习UI
  10. 自我监督学习和无监督学习_弱和自我监督的学习-第4部分