26、运行时保护机制:ASLR、DEP/NX、SEHOP、CFG(控制流防护),如何检查这些机制是否生效

各位同学,咱们今天聊点硬核的——运行时保护机制。说白了,就是操作系统在程序跑起来之后,怎么防着黑客搞破坏。我做了这么多年安全,见过太多漏洞被利用的案例,最后发现一个道理:没有这些保护机制,你的程序就像没锁门的房子

这四种机制——ASLR、DEP/NX、SEHOP、CFG——是现代操作系统的四大护法。咱们一个一个拆开讲,最后再教你怎么检查它们到底有没有生效。

ASLR:让黑客找不到北

ASLR的全称是Address Space Layout Randomization,地址空间布局随机化。嗯,名字挺长,但原理很简单:每次程序启动,系统把代码、数据、堆栈的基地址随机打乱

你想想看,如果没有ASLR,黑客写 exploit 的时候,直接硬编码一个地址就能跳过去执行恶意代码。但有了ASLR,他得先猜地址——猜错了程序就崩,猜对了才能继续。这就像你每次回家,门锁的密码都在变,小偷就算偷了钥匙也没用。

我在项目中遇到过一件事:有个老同事写了个网络服务,部署到新服务器上之后,发现 exploit 成功率从90%降到了5%。查了半天,原来是新系统默认开了ASLR。嗯,这就是ASLR的威力。

ASLR 的核心要点:

  • 随机化范围:栈、堆、共享库、可执行文件基址
  • 随机化粒度:Linux 上是页级(4KB),Windows 上是 64KB 对齐
  • 强度等级:Linux 有 0/1/2 三级,Windows 有强制开启选项

DEP/NX:不让数据区变成代码

DEP(Data Execution Prevention)和 NX(No-Execute)其实是一回事,只是不同平台叫法不同。Windows 叫 DEP,Linux 叫 NX。它的作用就一句话:数据区不能执行代码

你想想,传统的缓冲区溢出攻击,是把恶意代码写到栈或者堆里,然后跳过去执行。DEP/NX 直接把这个路子堵死了——栈就是栈,堆就是堆,你往里面写数据可以,但想当代码跑?门都没有。

我记得有一次做渗透测试,发现目标系统没开 DEP,一个简单的栈溢出就能 getshell。后来跟对方运维聊,他说「我觉着这功能没啥用就给关了」……我当时差点没背过气去。各位,DEP/NX 是底线,绝对不能关

注意:DEP/NX 不是万能的。它防不了 ROP(Return-Oriented Programming)攻击。ROP 不写新代码,而是把已有的代码片段拼起来用。所以后面才有了 CFG。

SEHOP:Windows 上的异常处理护盾

SEHOP(Structured Exception Handling Overwrite Protection)是 Windows 特有的机制。它保护的是异常处理链——说白了,就是防止黑客篡改你的异常处理函数指针。

在 Windows 上,每个线程都有一个 SEH 链,记录了异常发生时该调用哪个函数。老版本的 exploit 经常干这种事:覆盖 SEH 链上的某个指针,指向自己的恶意代码。SEHOP 会在异常触发前检查这个链的完整性——如果发现链断了或者指针不对,直接终止进程。

我个人习惯在 Windows 开发中,始终开启 SEHOP。虽然它只防 SEH 覆盖这一种攻击,但这一种就够要命的了。

CFG:控制流防护,堵死 ROP

CFG(Control Flow Guard)是微软在 Windows 8.1 和 Windows 10 上引入的。它解决的是 DEP/NX 防不了的问题——ROP 攻击。

CFG 的原理是:编译时记录所有合法的间接调用目标地址,运行时检查每个间接调用是否在合法列表里。如果发现你要跳到一个不在列表里的地址,直接 crash。

举个例子,你的程序里有个函数指针,正常情况指向函数 A。黑客通过漏洞把指针改成了函数 B。没有 CFG 的话,程序就傻乎乎地执行了 B。有 CFG 的话,系统会检查 B 是不是合法的间接调用目标——如果不是,直接报错。

我曾经在分析一个漏洞样本时,发现 exploit 在 Windows 10 上死活跑不起来。后来一查,是 CFG 拦住了它的 ROP 链。嗯,那一刻我对微软的好感度直接拉满。

如何检查这些机制是否生效

光知道原理不够,你得会检查。我整理了几种常用方法,按平台分。

Windows 平台

机制 检查方法 命令/工具
ASLR 查看进程的基址是否每次不同 Process Explorer / VMMap
DEP 查看进程的 DEP 状态 !process 0 0 进程名(WinDbg)
SEHOP 查看注册表或进程标志 GetProcessMitigationPolicy API
CFG 查看编译时是否启用 /guard:cf dumpbin /headers exe文件

具体操作:

  • ASLR:用 Process Explorer 打开一个 exe,看它的基址。关掉再打开,如果基址变了,说明 ASLR 生效。
  • DEP:在 WinDbg 里附加进程,输入 !process 0 0 进程名,看 Flags 里有没有 ExecuteDisable 标志。
  • SEHOP:写个小程序调用 GetProcessMitigationPolicy,检查 ProcessStrictHandleCheckPolicy 是否启用。
  • CFG:dumpbin /headers your.exe,在 DLL Characteristics 里找 0x4000(表示启用了 CFG)。

Linux 平台

机制 检查方法 命令/工具
ASLR 查看 /proc/sys/kernel/randomize_va_space cat /proc/sys/kernel/randomize_va_space
NX 查看进程的内存映射 cat /proc/pid/mapsexecstack
SEHOP Linux 没有 SEHOP(这是 Windows 特有的)
CFG Linux 没有 CFG,但有类似机制(如 Intel CET) readelf -l 可执行文件 查看 GNU_STACK 段

具体操作:

  • ASLR:执行 cat /proc/sys/kernel/randomize_va_space,返回 0 表示关闭,1 表示部分随机化,2 表示完全随机化。我建议设成 2。
  • NX:cat /proc/pid/maps 看栈和堆的权限,如果显示 rw-p 而不是 rwxp,说明 NX 生效。也可以用 execstack -q 可执行文件 检查。
  • CFG 类似机制:readelf -l 可执行文件,看 GNU_STACK 段有没有 E(可执行)标志。没有 E 就对了。

避坑指南:我曾经在检查一个 Linux 程序时,发现 /proc/pid/maps 里栈是 rwxp,说明 NX 没生效。查了半天,原来是编译时用了 -z execstack 选项。嗯,这个选项会强制栈可执行,千万别在生产环境用。

知识体系总览

下面这张图把四种机制的关系和检查方法串起来了。你可以把它当成一个速查表。

运行时保护机制知识体系 ASLR 地址随机化 DEP/NX 数据不可执行 SEHOP 异常链保护 CFG 控制流防护 ↓ 防御的攻击类型 ↓ 代码注入 地址猜解 栈/堆溢出 shellcode执行 SEH覆盖 异常劫持 ROP攻击 间接调用劫持 ↓ 检查方法 ↓ Win: Process Explorer Linux: /proc/.../va_space Win: WinDbg !process Linux: /proc/pid/maps Win: GetProcessMitigation Linux: 无此机制 Win: dumpbin /headers Linux: readelf -l 核心原则:多层防护,缺一不可。检查要勤,不要等到被攻击了才想起来。

写在最后

这四种机制,说白了就是四道防线。ASLR 让黑客找不到目标,DEP/NX 让数据区不能执行代码,SEHOP 保护异常处理链,CFG 堵死 ROP。每一道防线都不完美,但合在一起,就能挡住绝大多数攻击。

我个人习惯是:每次部署新程序,先跑一遍检查脚本。Windows 上用 Process Explorer 和 dumpbin,Linux 上用 cat 和 readelf。花不了几分钟,但能省掉后面的大麻烦。

嗯,今天就到这儿。记住一句话:安全不是功能,是习惯。


公众号:蓝海资料掘金营,微信deep3321