【转载】 Gcc 安全编译选项

news/2024/12/21 23:13:07/文章来源:https://www.cnblogs.com/wsg1100/p/18621522

【转载】Gcc 安全编译选项

转载信息:

本文来自博客园,作者:pwl999,转载请注明原文链接:https://www.cnblogs.com/pwl999/p/15534983.html

文章目录

目录
  • 【转载】Gcc 安全编译选项
      • 文章目录
  • 1. 简介
  • 2. NX(DEP)
  • 3. RELRO
  • 4. PIE(ASLR)
  • 5. CANARY(栈保护)
  • 6. FORTIFY
  • 7. RPATH/RUNPATH
  • 参考资料:

1. 简介

在编译器层面,gcc提供了不少安全方面的编译选项,主要有:

item opt descript
NX(DEP) -z execstack // 禁用NX保护 -z noexecstack // 开启NX保护 堆栈禁止执行
RELRO -z norelro // 关闭 -z lazy // 部分开启 -z now // 全部开启 GOT写保护
PIE(ASLR) -fpie -pie // 开启PIE,此时强度为1 -fPIE -pie // 开启PIE,此时为最高强度2 代码段、数据段地址随机化
CANARY -fno-stack-protector // 禁用 -fstack-protector // 开启 -fstack-protector-all // 完全开启 堆栈溢出哨兵
FORTIFY -D_FORTIFY_SOURCE=1 // 较弱的检查 -D_FORTIFY_SOURCE=2 // 较强的检查 常用函数加强检查

还有一个专门的checksec脚本来检测gcc编译出来的可执行文件,开启了哪些安全选项。 下载脚本:

git clone https://github.com/slimm609/checksec.sh/

使用checksec脚本检查:

$ ./checksec.sh/checksec --file=test
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable     FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   66) Symbols       No    0               1               test

2. NX(DEP)

NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。

gcc编译选项:

gcc -o test test.c					// 默认情况下,开启NX保护
gcc -z execstack -o test test.c		// 禁用NX保护
gcc -z noexecstack -o test test.c	// 开启NX保护
  • NX
$ gcc -z execstack -o test test.c
$ readelf -l testGNU_STACK      0x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000  RWE    10           // stack segment增加了可执行属性`E`
$ ./test &
[2] 64014
$ cat /proc/64014/maps 
...
7fff8910f000-7fff89130000 rwxp 00000000 00:00 0                          [stack]    // 运行时堆栈拥有可执行属性`x`
  • no NX
$ gcc -z noexecstack -o test test.c
$ readelf -l testGNU_STACK      0x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000000 0x0000000000000000  RW     10           // stack segment没有了可执行属性`E`
$ ./test &
[2] 64071
$ cat /proc/64071/maps 
...
7ffc72f09000-7ffc72f2a000 rw-p 00000000 00:00 0                          [stack]    // 运行时堆栈没有了可执行属性`x`

3. RELRO

在Linux系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域。 所以在安全防护的角度来说尽量减少可写的存储区域对安全会有极大的好处.
GCC, GNU linker以及Glibc-dynamic linker一起配合实现了一种叫做relro的技术: read only relocation。大概实现就是由linker指定binary的一块经过dynamic linker处理过 relocation之后的区域为只读.
设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击。RELRO为” Partial RELRO”,说明我们对GOT表具有写权限。

gcc编译选项:

gcc -o test test.c						// 默认情况下,是Partial RELRO
gcc -z norelro -o test test.c			// 关闭,即No RELRO
gcc -z lazy -o test test.c				// 部分开启,即Partial RELRO
gcc -z now -o test test.c				// 全部开启,即
  • No RELRO:

可以看到在程序运行以后,数据segment只对应一个vma区域,属性都是rw-

$ gcc -z norelro test.c -o test
$ ./test &
[1] 62725
$ cat /proc/62725/maps 
00400000-00401000 r-xp 00000000 fd:00 5320920                            /home/ipu/uid/test  // 代码segment
00600000-00601000 rw-p 00000000 fd:00 5320920                            /home/ipu/uid/test  // 数据segment
00af1000-00b12000 rw-p 00000000 00:00 0                                  [heap]
...

通过readelf命令读取segment信息,可以详细看到数据segemnt包含了哪些section:.init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 。

$ readelf -l test
Program Headers:Type           Offset             VirtAddr           PhysAddrFileSiz            MemSiz              Flags  AlignLOAD           0x0000000000000000 0x0000000000400000 0x00000000004000000x0000000000000824 0x0000000000000824  R E    200000LOAD           0x0000000000000828 0x0000000000600828 0x00000000006008280x000000000000023c 0x0000000000000240  RW     200000Section to Segment mapping:Segment Sections...02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss 
  • Partial RELRO:

可以看到加上relro编译选项以后,数据segemnt加载到内存分裂成了两个vma:
1、包含.got的vma,在动态链接完成后就被保护起来了,属性设置为r--
2、包含.data.bss的vma,在运行时还需要读写访问的,属性设置为rw-

$ gcc -z lazy test.c -o test
$ cat /proc/63607/maps 
00400000-00401000 r-xp 00000000 fd:00 5401237                            /home/ipu/uid/test  // 代码segment
00600000-00601000 r--p 00000000 fd:00 5401237                            /home/ipu/uid/test  // 数据segment(.init_array .fini_array .jcr .dynamic .got .got.plt)
00601000-00602000 rw-p 00001000 fd:00 5401237                            /home/ipu/uid/test  // 数据segment(.data .bss)
  • Full RELRO:

运行时的效果和Partial RELRO一样:

$ gcc -z now test.c -o test
$ ./test &
[2] 63766
$ cat /proc/63766/maps 
00400000-00401000 r-xp 00000000 fd:00 5401216                            /home/ipu/uid/test
00600000-00601000 r--p 00000000 fd:00 5401216                            /home/ipu/uid/test  // 数据segment(.init_array .fini_array .jcr .dynamic .got .got.plt)
00601000-00602000 rw-p 00001000 fd:00 5401216                            /home/ipu/uid/test  // 数据segment(.data .bss)

4. PIE(ASLR)

为了提升系统的安全,增大漏洞的攻击难度,提出了进程地址空间各区域随机化的措施,称之为ASLR(Address Space Layout Randomization)。ASLR通过随机放置进程关键数据区域的地址空间来防止攻击者能可靠地跳转到内存的特定位置来利用函数。现代操作系统一般都加设这一机制,以防范恶意程序对已知地址进行Return-to-libc攻击。

地址空间随机化分为3个等级:

0 关闭
1 半随机 code&data、stack、mmap、vdso随机化
2 全随机 在1的基础上加上heap随机化

可以通过/proc文件节点查询和配置aslr的等级:

$ cat /proc/sys/kernel/randomize_va_space

ALSR其中的code&data随机化需要gcc pie选项的支持。因为打开ASLR以后,支持exe文件code&data的随机化,所以需要把exe文件编译成位置无关代码,这种编译出来的exe文件格式为ET_DYN。可以使用-pie选项来编译ET_DYN类型的exe文件。

gcc编译选项:

gcc -o test test.c				    // 默认情况下,不开启PIE
gcc -fpie -pie -o test test.c		// 开启PIE,此时强度为1
gcc -fPIE -pie -o test test.c		// 开启PIE,此时为最高强度2
gcc -fpic -o test test.c		    // 开启PIC,此时强度为1,不会开启PIE
gcc -fPIC -o test test.c		    // 开启PIC,此时为最高强度2,不会开启PIE

说明:
PIE最早由RedHat的人实现,他在连接起上增加了-pie选项,这样使用-fPIE编译的对象就能通过连接器得到位置无关可执行程序。fPIE和fPIC有些不同。可以参考Gcc和Open64中的-fPIC选项.
gcc中的-fpic选项,使用于在目标机支持时,编译共享库时使用。编译出的代码将通过全局偏移表(Global Offset
Table)中的常数地址访存,动态装载器将在程序开始执行时解析GOT表项(注意,动态装载器操作系统的一部分,连接器是GCC的一部分)。而gcc中的-fPIC选项则是针对某些特殊机型做了特殊处理,比如适合动态链接并能避免超出GOT大小限制之类的错误。而Open64仅仅支持不会导致GOT表溢出的PIC编译。
gcc中的-fpie和-fPIE选项和fpic及fPIC很相似,但不同的是,除了生成为位置无关代码外,还能假定代码是属于本程序。通常这些选项会和GCC链接时的-pie选项一起使用。fPIE选项仅能在编译可执行码时用,不能用于编译库。所以,如果想要PIE的程序,需要你除了在gcc增加-fPIE选项外,还需要在ld时增加-pie选项才能产生这种代码。即gcc -fpie -pie来编译程序。单独使用哪一个都无法达到效果。

  • pie

使能pie编译选项以后胡,编译出来的可执行文件格式为ET_DYN,运行后数据段和代码段的起始地址也被随机化。

$ gcc -fpie -pie -o test test.c
$ file test
test: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=52206a970ad796ff8aa3e9b6e06ecdeaa14d0d8d, not stripped
$ ./test &
[1] 64253
$ cat /proc/64253/maps 
563dd3310000-563dd3311000 r-xp 00000000 fd:00 5401237                    /home/ipu/uid/test  // 代码段起始地址随机化
563dd3510000-563dd3511000 r--p 00000000 fd:00 5401237                    /home/ipu/uid/test  // 数据段起始地址随机化
563dd3511000-563dd3512000 rw-p 00001000 fd:00 5401237                    /home/ipu/uid/test$ readelf -l test
...
Program Headers:Type           Offset             VirtAddr           PhysAddrFileSiz            MemSiz              Flags  AlignLOAD           0x0000000000000000 0x0000000000000000 0x00000000000000000x0000000000000a0c 0x0000000000000a0c  R E    200000LOAD           0x0000000000000dd8 0x0000000000200dd8 0x0000000000200dd80x000000000000027c 0x0000000000000280  RW     200000
  • no pie

没有启用pie选项,编译出来的可执行文件格式为ET_EXE,运行后数据段和代码段的起始地址也和链接时的定义一致。

$ gcc -o test test.c
$ file test
test: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0b8ae05e348ea381550754279eb9973f473ccf7e, not stripped
$ ./test &
[1] 64300
$ cat /proc/64300/maps 
00400000-00401000 r-xp 00000000 fd:00 5355298                            /home/ipu/uid/test  // 代码段起始地址和elf中定义的加载地址一致
00600000-00601000 r--p 00000000 fd:00 5355298                            /home/ipu/uid/test  // 数据段起始地址和elf中定义的加载地址一致
00601000-00602000 rw-p 00001000 fd:00 5355298                            /home/ipu/uid/test$ readelf -l test
...
Program Headers:Type           Offset             VirtAddr           PhysAddrFileSiz            MemSiz              Flags  AlignLOAD           0x0000000000000000 0x0000000000400000 0x00000000004000000x0000000000000854 0x0000000000000854  R E    200000LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e100x000000000000023c 0x0000000000000240  RW     200000

5. CANARY(栈保护)

栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。
gcc在4.2版本中添加了-fstack-protector和-fstack-protector-all编译参数以支持栈保护功能,4.9新增了-fstack-protector-strong编译参数让保护的范围更广。

gcc编译选项:

gcc -o test test.c						    // 默认情况下,不开启Canary保护
gcc -fno-stack-protector -o test test.c     //禁用栈保护
gcc -fstack-protector -o test test.c        //启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码
gcc -fstack-protector-all -o test test.c    //启用堆栈保护,为所有函数插入保护代码

6. FORTIFY

fority其实非常轻微的检查,用于检查是否存在缓冲区溢出的错误。适用情形是程序采用大量的字符串或者内存操作函数,如memcpy,memset,stpcpy,strcpy,strncpy,strcat,strncat,sprintf,snprintf,vsprintf,vsnprintf,gets以及宽字符的变体。
gcc生成了一些附加代码,通过对数组大小的判断替换strcpy, memcpy, memset等函数名,达到防止缓冲区溢出的作用。

gcc编译选项:

gcc -o test test.c							// 默认情况下,不会开这个检查
gcc -D_FORTIFY_SOURCE=1 -o test test.c		// 较弱的检查
gcc -D_FORTIFY_SOURCE=2 -o test test.c		// 较强的检查

_FORTIFY_SOURCE设为1,并且将编译器设置为优化1(gcc -O1),以及出现上述情形,那么程序编译时就会进行检查但又不会改变程序功能。
_FORTIFY_SOURCE设为2,有些检查功能会加入,但是这可能导致程序崩溃。
gcc -D_FORTIFY_SOURCE=1 仅仅只会在编译时进行检查 (特别像某些头文件 #include <string.h>)
gcc -D_FORTIFY_SOURCE=2 程序执行时也会有检查 (如果检查到缓冲区溢出,就终止程序)

7. RPATH/RUNPATH

可以在编译时指定程序运行时动态链接库的搜寻路径,防止将一些动态库恶意替换,以达到攻击目的。

gcc –Wl,-rpath              // 指定运行时动态链接库的搜寻路径,硬编码进ELF文件 “RPATH”选项。
LD_RUN_PATH 环境变量         // 指定运行时动态链接库的搜寻路径,硬编码进ELF文件 “RPATH”选项。

查找动态库的过程中,大致的顺序是 RPATHLD_LIBRARY_PATHRUNPATH ,所以,如果使用的是 RPATH 用户将无法进行调整,所以建议使用 RUNPATH

gcc通过以下选项指定使用RPATH还是RUNPATH

-Wl,--disable-new-dtags     // 表明使用 RPATH 
-Wl,--enable-new-dtags      // 标示使用 RUNPATH 
  • RPATH
$ gcc -o test test.c -Wl,-rpath,./
$ readelf -d testDynamic section at offset 0xe18 contains 25 entries:Tag        Type                         Name/Value0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]0x000000000000000f (RPATH)              Library rpath: [./]...
  • RUNPATH
$ gcc -o test test.c -Wl,-rpath,./ -Wl,--enable-new-dtags
$ readelf -d testDynamic section at offset 0xe18 contains 25 entries:Tag        Type                         Name/Value0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]0x000000000000001d (RUNPATH)            Library runpath: [./]...

参考资料:

1、linux程序的常用保护机制
2、stack canary与绕过的思路
3、PIE与bypass思路
4、Canary保护详解和常用Bypass手段
5、GCC 安全编译选项
6、execve() 详解
7、Linux头文件和库的搜索路径

本文来自博客园,作者:pwl999,转载请注明原文链接:https://www.cnblogs.com/pwl999/p/15534983.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/856588.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用frida分析白盒aes,DFA攻击

这次分析的app是:五菱汽车(8.2.1) 登录,抓包发现请求体只有sd字段,看见加密的时候,可以先使用算法助手hook java层所有加解密方法发现我们所需要的sd加密字段在java层hook不到,那加密算法应该是写在了so层,因为这个app是bb加固企业,得有脱壳机才能脱。 jadx加载dex,直接…

2024 golang安装使用详细教程以及常见问题处理(附激活至2099年)

GoLand 简介 GoLand 是一款非常强大的 Go 语言集成开发环境,由JetBrains公司开发。它提供了丰富的功能和工具,帮助开发者更高效地编写、调试和部署代码。 下面这种方式仅供交流学习,如果有能力还请支持正版 下载安装 为了方便,也可以去链接取 点击获取安装包开始安装下载完成…

Infinite Pixels(无限像素)第五次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/rjjc这个作业的目标 小组成员分工完成选题的软件设计组长 祝方略-2022329301131组员1 娄涵格-2022329301112组员2 颜宇航-2022329301125组员3 常佳鑫-2022329301071一、团队介绍团队名称:Infinite Pixels(无限像素…

CMake构建学习笔记19-OpenSSL库的构建

详细介绍了在Windows和Linux环境下构建OpenSSL库的方法,并且如何通过CMake的方式被主程序调用。1. 概述 OpenSSL是一个开源的加密工具包和库,主要实现了安全套接字层(SSL)和传输层安全(TLS)协议,以及各种加密算法、数字签名、消息摘要、加密证书等功能。这个库可以说是W…

概率论沉思录:初等假设检验

我们在上一篇博客中介绍了传统的抽样理论。其中,我们导出了几种经典的抽样分布,也即给定关于所观察现象的假设H,数据D的概率分布p(D | H)。在上一篇博客中提到的伯努利坛子模型中,假设H即坛子的内容,数据D即重复抽球所生成的红球和白球序列。但正如我们我们在上一篇博客的…

开启Word、Excel、PPT时速度很慢的一种解决方法

本文介绍基于修改加载项,解决Microsoft Office系列软件开启速度较慢的办法~本文介绍基于修改加载项,解决Microsoft Office系列软件开启速度较慢的办法。最近,发现Excel软件的打开速度越来越慢,会在一定程度上影响工作效率。因此尝试对此加以解决。其中,本文所给方法对于Wo…

2024-2025-1 学号20241315《计算机基础与程序设计》第十三周学习总结

作业信息这个作业属于哪个课程 <班级的链接>2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>https://www.cnblogs.com/rocedu/p/9577842.html#WEEK13这个作业的目标 <写上具体方面>第12章并完成云班课测试作业正文 ... 本博客链接 h…

【解决方案】电商精细化运营方案

随着互联网技术的不断发展和普及,电商行业在过去几十年中取得了巨大的发展和变革。从供小于求的“以商品为主”阶段,到享受时代红利的“以流量为主”阶段,再到重视消费者体验的“精细化运营”阶段,电商市场正在进入以消费者为中心精细化运营时代,这要求电商企业从存量市场…

洛谷 P11411 兰奇的卡牌游戏——题解

洛谷P11411兰奇的卡牌游戏传送锚点摸鱼环节 兰奇的卡牌游戏 题目描述 作为制卡大师的兰奇,发明了一种自助型卡牌游戏。 给定 \(n\) 张卡牌,第 \(i\) 张卡牌编号为 \(i\),其权值为 \(a_i\),卡牌的权值互不相同。 这个卡牌游戏的规则需要自己生成。一开始,所有的牌都在备选区…

centos上redis的安装

官网教程 redis安装官网 https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/ 可以右下方看到安装到各个平台的连接 这里我安装的是centos系统,所以选择 install Redis on Linux centos系统选择red hat安装方式下方第一条命令需要输入【y】进行确认 s…

CHM助手 高效制作接口文档

1 CHM助手 >> 高效制作接口文档 1.1 概述用户如果书写代码的过程中使用了良好的注释,比如:doxygen规范, 则有可能生成比较规范的接口文档。很多工具软件都支持编程扩展,比如:宏/脚本接口,那么,完善的接口文档将会给用户带来极大的便利,否则,软件的使用和推广都会…