程序编译保护机制
本篇文章主要内容摘选自 Linux程序的常用保护机制、GCC 安全编译选项、GCC安全保护机制,在本篇文章中,主要梳理汇总,便于以后查阅。
操作系统内置的安全机制
此处只总结和程序执行过程相关的安全机制,其他种类的安全机制与本文无关,暂不介绍。
Windows
-
DEP,全程为
Data Execution Prevention
,Windows系统内置的内存保护机制,自从XP和Server 20003开始引进。DEP使得系统能够标记一个或多个内存页的属性为不可执行,这意味着代码不能在该内存页中执行,这有助于缓解缓冲区溢出攻击的危害。如果一个应用尝试在受保护的内存页中运行代码,将会触发内存访问异常,如果应用未处理该异常,默认处理会终止该进程。 -
ASLR,
Address Space layout randomization
加载地址随机化机制,开启方式:VS开发环境中的链接器下的高级选项中可以设置映像随机化、堆栈随机化、PEB和TEB随机化等。
-
GS机制,缓冲区安全检查,开启此功能,编译器会为每个函数调用的入口增加额外的随机数(该随机数称为canary),它位于EBP之前,同时在.data内存区存放该随机数副本。当函数栈发生溢出时,它会被覆盖,函数在返回之前会比较.data区中副本的值和栈帧真实值,如果两者不相等,则触发异常处理流程。
开启方式:VS开发环境中的C/C++下的代码生成中的开启缓冲区安全检查。
Linux
-
NX机制,No-Execute,同Windows上的DEP功能类似,将数据所在内存页标志为不可执行,当程序溢出转入shellcode时,会尝试在数据页上执行指令,此时CPU会抛出异常。
关闭NX机制,编译时增加 -z execstack
开启NX机制,编译时增加 -z noexecstack(默认开启) -
PIE机制,Position-independent executables,位置独立的可执行区域。同Windows系统的ASLR功能类似,一般同NX机制配合使用,能有效组织在堆栈上运行恶意代码。PIE机制有三种工作模式,
- 工作模式0:关闭进程地址空间随机化
- 工作模式1:开启mmap机制、stack和vdso的地址随机化
- 工作模式2:在1的基础上,增加堆地址随机化
系统级别关闭PIE echo 0 > /proc/sys/kernel/randomize_va_space
开启PIE的工作模式1,在编译时增加 -fpie -pie
开启PIE的工作模式2,在编译时增加 -fPIE -pie(默认开启)
系统级别的PIE决定程序运行栈和堆段的地址随机化。
编译器的PIE选项决定程序静态段(bss、data、text)地址随机化。
GCC编译器中的参数PIE和PIC都可生成位置无关的代码,PIE主要用在可执行文件上,PIC用在共享库上。
-
Cannary栈保护,同Windows上的GS机制,一种预防缓冲区溢出的手段,通常攻击者通过覆盖函数调用栈的返回地址来执行shellcode,在启动栈保护机制后,在函数开始执行时会往栈里插入cookie信息,当函数真正返回时会验证cookie信息是否合法,不合法则终止程序执行。Linux把这种在编译期间插入的信息称之为Canary。
开启Cannary栈保护,在编译时增加 -fstack-protector(只为含char数组的函数加入保护代码) 和 -fstack-protector-all(为所有函数加入保护代码)
关闭Cannary栈保护,在编译时增加 -fno-stack-protector(默认不开启)
Cannary机制还会调整局部变量的顺序。如果数组地址在其他变量地址下面,那么数组缓冲区溢出后,可能修改其他变量的数值,当其他变量是函数指针时,就可被跳转到shellcode上执行。将将数组移到高位地址后,缓冲区溢出的地址面对的是Cannary值保护,这样可加大溢出攻击的难度。这种保护方法只对函数栈中的控制信息(cannary word,EBP)和返回地址进项保护,没有对局部变量进行保护。
-
RelRo机制
GCC, GNU linker以及Glibc-dynamic linker一起配合实现了一种叫做relro的技术(read only relocation)。大概实现就是由linker指定binary的一块经过dynamic linker处理过之后的区域为只读。设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击。全部开启RelRo机制:在编译时增加 -z now
部分开启RelRo机制:在编译时增加 -z lazy(默认配置)
关闭RelRo机制: 在编译时增加 -z norelro
查看可执行文件安全机制开启情况
通过检查可执行文件的属性来查看安全机制开启情况,可以使用 checksec来查看。