核心思路是让恶意代码难以写入、无法执行、找不到落脚点。需从内存防护(DEP/NX、ASLR、Stack Canary)、二进制加固(Full RELRO、禁用危险函数、剥离符号)、运行时限制(最小权限、seccomp/Job Objects、内存行为监控)三方面协同防御。

核心思路是让恶意代码难以写入、无法执行、找不到落脚点。内存注入类攻击(如shellcode注入、ROP链构造)高度依赖可预测的内存布局、可执行的栈/堆、以及未受保护的关键函数入口,加固要从这三个环节切入。
启用并验证基础内存防护机制
这是最直接有效的防线,需确认系统和程序两级均已开启:
-
DEP/NX(数据执行保护):确保栈和堆内存页标记为“不可执行”。Linux下通过
readelf -l 程序 | grep GNU_STACK检查是否含GNU_STACK且无WWE标志;Windows可通过systeminfo命令查看“数据执行保护状态”。 -
ASLR(地址空间布局随机化):强制每次加载时栈、堆、共享库基址随机变化。Linux检查
/proc/sys/kernel/randomize_va_space值是否为2;编译时加-pie -fPIE生成位置无关可执行文件,使整个程序也能被随机加载。 -
Stack Canary(栈保护):在函数栈帧中插入校验值(canary),返回前验证其完整性。用
gcc -fstack-protector-strong编译关键程序,再用checksec --file 程序确认canary已启用。
强化二进制程序自身防护属性
仅靠系统级防护不够,程序本身需主动加固:
-
启用Full RELRO:防止GOT表(全局偏移表)被篡改。编译时添加
-Wl,-z,relro,-z,now,使动态链接符号表在启动时即重定位并设为只读,阻断常见的“write-what-where”利用链。 -
禁用危险函数调用:在源码中避免使用
strcpy、gets、sprintf等不带长度检查的函数;启用_FORTIFY_SOURCE=2编译选项,让GCC在编译期对memcpy、strncpy等函数做额外边界检查。 -
剥离调试与符号信息:发布前运行
strip 程序,移除符号表和调试段。这虽不防漏洞,但大幅增加攻击者逆向分析难度,延缓漏洞利用链构建。
限制运行时环境与权限
即使二进制被绕过,也要让注入代码难有作为:
-
以最小权限运行:关键服务不要用root或SYSTEM账户启动。Linux下用
setuid/setgid降权,或通过systemd配置DynamicUser=yes;Windows下配置服务登录身份为专用低权限账户。 -
启用seccomp-bpf(Linux)或Job Objects(Windows):对进程施加系统调用白名单。例如,一个只处理网络请求的程序,可禁止
execve、mmap(带PROT_EXEC)、ptrace等高危调用,从根源上封死shellcode执行路径。 -
监控异常内存行为:部署EDR或主机IDS,对进程内出现的
mprotect将内存页设为可执行、或VirtualProtect修改PAGE_EXECUTE_READWRITE等操作进行实时告警与拦截。

















