checksec 可以查看程序开启了哪些保护。
➜ ~ checksec /bin/ls
[*] '/bin/ls'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled
Canary
canary 是一种防止缓冲区溢出攻击的保护机制。它的基本思想是在程序的堆栈中插入一个随机生成的数值,用于检测缓冲区溢出攻击。
.text:0000000000001189 endbr64
.text:000000000000118D push rbp
.text:000000000000118E mov rbp, rsp
.text:0000000000001191 sub rsp, 30h
.text:0000000000001195 mov rax, fs:28h
.text:000000000000119E mov [rbp-8], rax
...
.text:00000000000011CE mov rdx, [rbp-8]
.text:00000000000011D2 xor rdx, fs:28h
.text:00000000000011DB jz short locret_11E2
.text:00000000000011DB
.text:00000000000011DD call ___stack_chk_fail
.text:00000000000011DD
.text:00000000000011E2 ; --------------------------------------------------------
-------------------
.text:00000000000011E2
.text:00000000000011E2 locret_11E2: ; CODE XREF:
f+52↑j
.text:00000000000011E2 leave
.text:00000000000011E3 retn
canary 的初始值存储在 tls 中,也就是前面提到的 stack_guard 。
在编译 c 程序时使用 -fno-stack-protector 参数可以关闭 canary 保护(注意高版本的 gcc 的 canary保护关不掉)。
NX
NX 即 No-execute(不可执行),NX 的基本原理是将数据所在内存页标识为不可执行,也就是同一内存可写与可执行不共存。
gcc 编译器默认开启了 NX 选项,如果需要关闭 NX 选项,可以给 gcc 编译器添加 -zexecstack 参数
PIE
PIE 主要随机了代码段( .text ),初始化数据段( .data )和未初始化数据段( .bss )的地址。另
外 PIE 是否开启还会影响堆的基址。
开启 PIE:
关闭 PIE:
在编译 c 程序时使用 -no-pie 参数可以关闭 PIE 保护。
ASLR
ASLR 是系统级别的地址随机。通过修改 /proc/sys/kernel/randomize_va_space 的值可以控制
ASLR 的级别:
0:关闭 ASLR
1:栈基址,共享库,mmap 基址随机
2:在 1 的基础上增加堆基址的随机
关闭 PIE
关闭 ASLR: 主模块加载地址固定(0x400000)所有模块加载地址固定
开启 ASLR:主模块加载地址固定(0x400000) 其他模块加载地址不固定
开启 PIE
关闭 ASLR:所有模块加载地址固定 主模块地址(主模块基址 0x55xxxxxxxxxx且固定)
开启 ASLR:所有模块加载地址不固定
RELRO
当 RELRO 保护为 NO RELRO 的时候, init.array 、 fini.array 、 got.plt 均可读可写。
为 PARTIAL RELRO 的时候, init.array 、 fini.array 根据实际调试结果判断是否可写,
got.plt 可读可写。
为 FULL RELRO 时, init.array 、 fini.array 、 got.plt 均可读不可写。
-Wl,-z,norelro 编译参数可以关闭 RELRO ,使 RELRO 状态变为 NO RELRO 。
-Wl,-z,lazy 会开启延迟绑定,使 RELRO 状态变为 Partial RELRO 。