二进制程序的一些保护措施

二进制程序的一些常见保护。

1、ASLR

aslr是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的的一种技术。也就是说程序每次执行时,栈、堆、库的位置都不一样。

效果如下所示:

//环境:gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)
#include

int main()
{
    int x=0;
    printf("%08lX\n",&x);//打印变量x在栈中的地址
}

结果如下:

ex@ex:~/test$ ./a.out 
7FFEDE67D2E4
ex@ex:~/test$ ./a.out 
7FFFCD469C84
ex@ex:~/test$ ./a.out 
7FFD6501FE14
ex@ex:~/test$ ./a.out 
7FFE10E29F94
ex@ex:~/test$ ldd a.out 
    linux-vdso.so.1 (0x00007ffc2f368000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdf818c9000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fdf81ebc000)
ex@ex:~/test$ ldd a.out 
    linux-vdso.so.1 (0x00007fff33fbc000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8b8d00a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f8b8d5fd000)
ex@ex:~/test$ ldd a.out 
    linux-vdso.so.1 (0x00007fff4a1bd000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff285a6f000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff286062000)
ex@ex:~/test$ ldd a.out 
    linux-vdso.so.1 (0x00007ffc4d39e000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f988480b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f9884dfe000)

ASLR(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。据研究表明ASLR可以有效的降低缓冲区溢出攻击的成功率,如今Linux、FreeBSD、Windows等主流操作系统都已采用了该技术。

Linux检查是否开启ASLR,可用下面命令:

cat /proc/sys/kernel/randomize_va_space

如果/proc/sys/kernel/randomize_va_space里的值为0时,则表示ASLR关闭。

可用下面的命令手动关闭:

echo -n "0" > /proc/sys/kernel/randomize_va_space

-n表示不输出换行

Windows10强制开启ALSR,但是可以通过更改PE文件头里的Optional Header结构体里的DLL Characteristics字段,将DLL Characteristics字段的第7位设置为0即可关闭栈的ASLR,但是系统动态库的ALSR是强制开启的,也可以使用PEtools进行更改,如下图:

2、DEP

数据执行保护,默认栈的权限是可读、可写、不可执行。

gcc编译器默认开启该保护,编译时加上 -z execstack 则关闭该保护,-z noexecstack 是开启该保护。(-z 是传参给链接器,execstack是使目标文件的栈可以执行)

3、PIE

PIE(position-independent executable, 地址无关可执行文件)技术就是一个针对代码段.text, 数据段.*data,.bss等固定地址的一个防护技术。同ASLR一样,应用了PIE的程序会在每次加载时都变换加载基址。

gcc编译器 编译时加上-fpie -pie即开启 PIE,原先是默认不开启的,现在好像是默认开启,编译时加上 -no-pie 关闭PIE保护。没有开启的情况下.text, 数据段.*data,.bss等段的地址是固定的。

4、Stack Guard

编译器对栈溢出的一种保护机制,在函数执行时,先在栈上放置一个随机标识符,函数返回前会先检查标识符是否被修改,如果被修改则直接触发中断来中止程序,可以有效的防止栈溢出攻击。

gcc默认开启 Stack Guard ,编译时加上 -fno-stack-protector 参数就可以关闭 Stack Guard(CANARY)。

5、RELRO

relro 是一种用于加强对 binary 数据段的保护的技术。relro 分为 partial relro 和 full relro。参数 -z norelro 是关闭RELRO保护。
Partial RELRO
现在gcc 默认编译就是 partial relro,参数是 -z relro
部分区块(比如:.init_array .fini_array .jcr .dynamic .got)在被动态装载(初始化)后,就被标记为只读区块。
Full RELRO
gcc编译参数是-z relro -z now
拥有 Partial RELRO 的所有特性
所有导入的符号都在 startup time 被解析

关闭fastbin

#include <malloc.h>

// mallopt(1, 0);
mallopt(M_MXFAST, 0);

禁止SYS_execve系统调用

#include <sys/prctl.h>

// prctl(38, 1LL, 0LL, 0LL, 0LL);
prctl(PR_SET_NO_NEW_PRIVS, 1LL, 0LL, 0LL, 0LL);

在Linux中,PR_SET_NO_NEW_PRIVS 当一个进程或者子进程设置了PR_SET_NO_NEW_PRIVS属性,则其不能访问一些无法share的操作,这是kernel 3.5后加的feature。

AddressSanitizer 内存访问越界检查

需要安装的库:libasan.x86_64,新版本的gcc可能还需要安装libubsan,虽然说AddressSanitizer是gcc的一部分,但这两库默认是没有安装的。

使用方法很简单,只要在编译程序时加上-fsanitize=address -fno-omit-frame-pointer两个编译选项即可,需要说明的是要使用系统自带的内存管理库,不能使用第三方的内存管理库,因为这个功能要拦截malloc,free等标准函数。gcc几个常用编译选项如下:

-fsanitize=address #开启地址越界检查功能

-fno-omit-frame-pointer #开启后,可以出界更详细的错误信息

-fsanitize=leak #开启内存泄露检查功能

Undefined Behavior Sanitizer 未知行为检测

UBSan有一些处理程序或魔术功能入口点,它们被称为未定义的行为。编译仪器代码通过适当注入检查;如果检查代码检测到UB,则调用这些处理程序。

它的一个gcc编译标志(-fsanitize=undefined),用于添加运行时检测代码。

说点什么

avatar
  Subscribe  
提醒