参考:
Canary
简单地说:
- 函数在调用时,在返回地址与局部变量之间设置了一个用户不可知的
Canary
; - 在函数结束调用时,函数检查这个
Canary
是否被修改,否则抛出异常;
gcc
在编译时可以控制以下的几个参数控制栈的保护程度:
|
|
Fortify
Fortify
是 gcc
的一个检测工具,它会在编译时检测危险的字符串操作函数,比如 memcpy
、strcpy
等。
它有弱强两种使用模式:
D_FORTIFY_SOURCE
设置为 1 进行较弱的检查:- 程序编译时就会进行检查,但是不会改变程序的功能;
- 程序仅仅在编译时进行检查,运行时不会检查;
1
$ gcc -D_FORTIFY_SOURCE=1 t.c
D_FORTIFY_SOURCE
设置为 2 进行较强的检查:- 程序编译时可能会改变程序执行的函数,可能会导致程序崩溃;
- 程序在运行时会进行检查,检查到缓冲区溢出会终止程序;
1
$ gcc -D_FORTIFY_SOURCE=2 t.c
NX (DEP)
这一技术的基本原理是将数据所在的内存页标注为不可执行,程序试图在数据上执行代码时,CPU 会抛出异常。
gcc
默认开启了 NX
选项,可以通过以下的方式控制 NX
保护:
|
|
PIE (ASLR)
PIE: Position Independent Executable(位置独立可执行)。gcc
通过以下的方式控制是否开启 PIE
:
|
|
但是在 Linux 平台下,即使文件开启了 PIE 保护,还需要系统开启 ASLR 才会打乱基址,否则程序仍然会加载在一个固定的基址上(只不过和不开启 PIE 不一样)。
我们可以通过控制文件 /proc/sys/kernel/randomize_va_space
控制是否开启 ASLR:
0
:表示关闭进程地址空间随机化。1
:表示将 mmap 的基址,stack 和 vdso 页面随机化。2
:表示在 1 的基础上增加堆区基址的随机化(下图中的Random brk offset
)。
Relro
gcc
、gnu linker
、glic-dynamic-linker
一起配合实现了一种叫做 Relro
的技术(Read Only Relocation)。
实现方式就是通过 linker 指定文件的的部分区域标记为只读区域。
在 gcc
中指定以下的参数可以控制编译的方式:
|
|