Windows系统之DEP(Data Execution Prevention)
原创
ITPAPA
ITPAPA
ITPAPA
2026年10月19日 18:01
江苏
去阅读
DEP 数据执行保护
DEP 让处理器拒绝从不可执行的数据页取指。它把堆、栈等数据区域与可执行代码区分开,阻断把数据直接当作机器指令执行的一类攻击。[1]
以受支持的 Windows 11 x64 为主要验证环境,兼顾 Windows 10 与 Windows Server。硬件 DEP 依赖处理器 NX 或 XD 能力;32 位旧应用的兼容设置不能推广到所有架构。
逻辑架构与请求流
图 1 配置进入执行组件,请求经过检查后产生结果与后续处理。图示为职责关系,非固定进程或调用栈。
保护边界
DEP 不判断文件是否恶意,也不修复越界写入。已具有执行权限的代码仍可运行;合法 JIT 通过受支持的内存权限转换生成代码,因此 DEP 与禁止动态代码的 ACG 不能等同。
01 运行逻辑与关键参数
1 进程创建时,系统综合架构约束、映像属性及进程缓解策略,决定 DEP 行为。64 位进程通常始终受硬件 DEP 保护,不应把旧式逐应用排除当作通用修复。
2 VirtualAlloc 或映像映射建立页权限;数据页通常不带执行权限。内存管理器将抽象的 PAGE\_READWRITE 等权限转换为硬件页表属性。
3 处理器从某虚拟地址取指时进行地址转换与权限检查。若目标页不可执行,则产生异常,Windows 可向用户态报告执行型访问冲突。
4 异常未处理时进程终止并进入错误报告流程。排障应追溯谁把指令指针或函数指针指向数据,而非仅检查发生异常的系统 DLL。
关键参数与判读
| 参数或对象 | 位置或类型 | 功能与判读 |
|---|---|---|
| NX\_COMPAT | PE DllCharacteristics 标志 | 声明映像兼容 DEP;用 /NXCOMPAT 构建 |
| Enable 与 Permanent | PROCESS\_MITIGATION\_DEP\_POLICY | 查询进程实际状态;Permanent 表示不可再放宽 |
| PAGE\_READWRITE | 内存页保护 | 可读写,不可执行 |
| PAGE\_EXECUTE\_READ | 内存页保护 | 可读执行,通常用于代码 |
| NX 启动策略 | BCD 中 nx | 历史系统级兼容策略;不用于日常全局关闭 |
参数表区分编译属性、配置意图与运行状态。字段存在不等于当前版本可写;SDK 结构中保留位不得自行赋值。
02 底层对象与实现机制
页权限从映像节到实际页面
PE 节属性描述映像的初始保护意图,内存管理器按页面粒度建立映射。VirtualQuery 返回 MEMORY\_BASIC\_INFORMATION,其中 State 区分提交、保留和空闲,Type 区分映像、映射和私有内存,Protect 表示当前区域保护。文件中某节叫 text 并不能证明当前页可执行;故障调查必须读取实际 Protect。[D1][D2]
执行访问冲突与缺页不是同一个结论
CPU 检查取指地址的转换和执行权限。未映射地址、已释放地址、不可执行的有效数据页都可能产生执行访问冲突。ExceptionInformation[0]=8 只说明访问种类,不能自动证明是有效 NX 页触发。把异常目标和 VirtualQuery 或 !address 的区域属性结合,才能区分指针悬空与权限约束。
JIT 的正确生命周期
常见安全设计先分配 RW,写入代码,再切换为 RX,并按平台要求刷新指令缓存。它避免同时可写可执行,但不意味着绕过其他缓解:ACG 可禁止 RW 转 RX,CFG 可能要求动态目标有效性,CET 还约束返回和上下文。释放代码前必须保证没有线程和回调仍引用该区域。
对象和证据对照
| 对象或数据结构 | 技术职责 | 可观测与判读 |
|---|---|---|
| MEMORY\_BASIC\_INFORMATION | BaseAddress RegionSize Protect State Type | 以完整区域和权限解释故障地址 |
| EXCEPTION\_RECORD | ExceptionCode 与 ExceptionInformation | 区分读 写 执行及目标地址 |
| PE DllCharacteristics | NX\_COMPAT | 静态兼容属性,不替代页权限 |
| 进程 DEP policy | Enable Permanent | 查询实际进程,不只看注册表 |
| 指令与异常上下文 | RIP 或 EIP 寄存器 | 还原跳转来源与目标 |
03 执行时序与检查边界
沿一次请求依次观察输入、状态、检查位置、输出和失败去向。以下为职责级时序,不把图中角色强行对应为固定函数或独立进程。
图 2 请求和结果的时序示意。自指箭头表示角色内部处理,失败去向不必是可恢复的业务返回。
检查点发生在取指,不是每次写入数据时。越界写破坏函数指针可能早已发生,最后一次跳转才暴露问题。
异常处理器能够记录上下文,但不应把持续执行受损进程作为修复。正确修复要回到指针产生、代码页保护和释放时序。
观测与证明的区别
静态属性证明构建或配置意图,运行查询证明当前对象状态,事件和转储证明某次路径发生过什么。至少让两类证据相互支持;当接口失败、符号不匹配或负载未覆盖时,明确标记未知。
04 组件文件与基础诊断
| 文件或对象 | 职责 | 排障关注点 |
|---|---|---|
| %SystemRoot%\System32\ | ||
| toskrnl.exe | 内存管理和异常分发 | 核心系统文件,不手工替换 |
| %SystemRoot%\System32\ | ||
| tdll.dll | 用户态异常与 NT 系统调用入口 | 符号须与系统版本匹配 |
| 目标 EXE 与 DLL | PE 属性与故障代码 | 记录 SHA256 和产品版本 |
| 进程页表与 VAD | 执行权限的运行态证据 | 在合适转储或调试会话中检查 |
以下以提升权限的 Windows PowerShell 5.1 为常见查询环境。dumpbin 和 signtool 需 Visual Studio 或 WDK;WinDbg 命令在调试会话执行。预先准备可写的 C 盘 Lab 测试目录,示例路径、进程名与域账号按现场替换,导出文件避免覆盖原证据。
Get-ProcessMitigation -System
Get-ProcessMitigation -Name demo.exe
Get-ProcessMitigation -Name demo.exe -RunningProcesses
dumpbin /headers C:\Lab\demo.exe
WinDbg 在故障转储内执行
!analyze -v
.exr -1
.ecxr
!address @rip
事件与错误解释
Application 日志中的 Application Error 1000 与 Windows Error Reporting 1001 可提供时间和故障模块,但不足以证明 DEP。异常码 0xC0000005 的 ExceptionInformation[0] 为 8 表示执行访问冲突;还须确认目标区域存在且不可执行。x86 将 @rip 换为 @eip。
诊断资料可能包含账号、文件路径与业务数据。保存原始证据,分析使用副本;共享前只保留定位问题所需信息。
05 实操实验与结果解释
读取一块私有页的权限而不执行其中内容
使用 Visual Studio 的 x64 Native Tools 命令行,保存为 page\_probe.cpp。该样例只分配和查询 RW 页,不构造机器码,也不制造崩溃。
实验约定 先准备C盘Lab目录与测试数据。C++样例使用匹配架构的Visual Studio和Windows SDK;源码与命令以代码注释区分。样例需在目标Windows环境编译或执行后填写实测记录。
include
include
int main() {
void\* p = VirtualAlloc(nullptr, 4096,
MEM\_RESERVE | MEM\_COMMIT, PAGE\_READWRITE);
if (!p) { printf(\"alloc=%lu\
\",GetLastError()); return 1; }
MEMORY\_BASIC\_INFORMATION m{};
SIZE\_T n = VirtualQuery(p, &m, sizeof(m));
if (!n) printf(\"query=%lu\
\", GetLastError());
else printf(\"state=%lx type=%lx protect=%lx\
\",
m.State, m.Type, m.Protect);
VirtualFree(p, 0, MEM\_RELEASE);
return n ? 0 : 2;
}
// cl /W4 /EHsc page\_probe.cpp /link /NXCOMPAT
预期结果与证据限制
1 正常情况下 State 对应 MEM\_COMMIT、Type 对应 MEM\_PRIVATE、Protect 对应 PAGE\_READWRITE;按头文件常量解释,不凭十六进制字符串猜测。
2 此实验验证页属性,不证明全进程 DEP 覆盖。再查询目标进程缓解状态;32 位 DEP 查询与现代 64 位架构限制分别处理。
3 发生真实崩溃时保留 .exr -1、.ecxr、kv、!address 的成组输出,标明采集自同一转储与线程。
06 验证流程与故障分流
验证 1
基线:查询已运行目标进程的 DEP 状态;记录 EXE 架构、PE NX\_COMPAT、进程 ID 与启动时间。预期结果为策略与架构约束一致。
验证 2
功能:仅在隔离实验进程中分配 RW 页并尝试执行无害测试指令。预期出现执行访问冲突,保留异常记录与页权限。测试进程崩溃是预期结果。
验证 3
兼容:运行受支持的 JIT 工作负载并观察合法 RX 页。预期业务正常;若失败,应检查运行时是否遵循写入后转执行的协议。
常见问题判断表
| 现象 | 优先检查 | 处理方向 |
|---|---|---|
| 0xC0000005 | 看异常参数及目标页 | 读写冲突不能直接归为 DEP |
| 仅 32 位旧版失败 | 比对架构与动态代码路径 | 先升级运行时 |
| 找不到独立 DEP 服务 | 核查页权限和进程策略 | 该功能没有独立服务开关 |
排障证据与验收记录
先记录 Windows 版本与构建、处理器架构、相关软件和驱动版本、策略来源及最近变更。随后对齐时间、进程或设备标识、文件哈希、错误码和日志正文;缺少关联时保留为待验证假设。
验收至少保留配置结果、重启或重启应用后的运行状态、合法工作负载结果、无害负向测试结果以及恢复验证。远程环境缺少物理条件的项目应列为未测,不以命令执行成功代替功能通过。
07 互操作版本与性能分析
| 关联对象 | 机制关系 | 现场决策 |
|---|---|---|
| DEP 与 ACG | DEP 约束取指,ACG 约束动态执行内存生成 | RW 转 RX 能否成功需单独验证 |
| DEP 与 CFG | 一个检查页执行权限,一个检查调用目标 | 可执行页也可能不是合法 CFG 目标 |
| DEP 与 ASLR | 权限限制与地址随机化互补 | 地址变化不能证明页不可执行 |
| x86 与 x64 | API 可配置性和强制约束不同 | 不要把32位兼容排除套到64位进程 |
版本和平台
故障性能分析应分离异常路径和正常路径。DEP 检查主要依靠硬件页权限,不能把应用所有 CPU 高占用都算为 DEP 开销。
覆盖和证据
映像标志、进程状态和具体页权限分别采集;任何一个缺失都只能说明部分状态。
性能与恢复
应用自身建立的永久策略未必能由事后管理设置放宽。恢复应新建进程验证,不在已损坏进程里继续试错。
量化验证方法
以同设备、同版本、同输入和同运行模式做前后对照,记录样本数、预热、吞吐、P95或P99延迟、CPU与失败率。计时比较前先确认目标保护实际运行,避免把功能未启动或业务降级误认为优化成功。涉及启动、登录或外设的功能还应记录状态转换和时间线。
08 典型排障案例与最佳实践
以下为按机制设计的演练案例,用于说明证据链与处理方法,不代表公开披露的真实事故。
案例 1 旧报表插件打开即崩溃
证据 异常为执行访问冲突,IP 落在堆中;调用链指向插件自建跳板。
根因判断 插件依赖可执行数据页或发生指针破坏。不能单凭 DEP 开启就断定误报。
处理 升级插件并修复内存权限与生命周期;让供应商提交同版本符号。
复测 保持 DEP 开启,重复导入、计算与导出,确认无执行型冲突。
案例 2 升级后系统 DLL 被报为故障模块
证据 WER 显示 ntdll.dll;异常上下文却是应用回调跳到已释放堆。
根因判断 系统 DLL 是异常分发路径,原因为应用 use after free。
处理 采集完整用户态转储;在测试环境用堆验证定位最早破坏点。
复测 同一输入与并发条件下复测,并确认堆错误消失。
部署与恢复原则
开发侧保留 /NXCOMPAT,运行时避免长期 RWX 页。对无法修复的遗留程序采用隔离运行与有期限的兼容决策,记录例外作用范围;恢复时撤销应用覆盖并重新启动应用,不以全局 BCD 放宽作为标准方案。
处理顺序为先收集证据,再最小范围复现,优先修复应用、驱动或策略缺口,最后复测保护与业务。确需临时兼容配置时,记录责任人、作用对象、到期时间和恢复条件,验证后明确撤销。
09 深入排障演练与根因验证
本章为机制推导的完整演练,不是实际事故复盘。步骤中的预期与假设必须由现场证据验证,不能直接作为客户环境结论。
1 复现条件:特定并发导出后进程崩溃,表面故障模块是系统异常分发代码。
2 假设拆分:NX 权限不兼容、未映射跳转、释放后回调三种假设分别列证据。
3 证据读取:异常参数显示执行访问;!address 报目标为 MEM\_FREE,则不能把结论写成已提交 RW 页的 NX 保护。
4 时间线重建:从回调注册、取消和对象销毁日志找出释放先于最后一次回调的顺序。
5 定位与修复:增加引用计数和注销等待,确保最后使用者退出后才释放代码或对象。
6 反证测试:仅调整 DEP 不会解决生命周期缺陷;修复后保持原保护进行同负载复测。
7 验收:相同输入和并发下无悬空目标,正常路径结果一致,原有缓解状态保持;样例结论不替代现场转储分析。
提交研发或供应商的最小资料集
提供稳定复现步骤、系统构建、架构、对象版本与哈希、有效策略及运行状态、原始错误和相同时间范围日志。涉及崩溃补充匹配转储与符号,涉及驱动补充INF CAT SYS和设备实例,涉及认证保留协议与账号类型。报告分开写观察事实、根因假设、修复动作与复测结果。
10 配置部署与恢复
1 在 Windows 安全中心进入 应用和浏览器控制 漏洞利用防护,核对系统和目标程序 DEP 配置;将应用例外限制在已验证的架构和版本。
2 开发构建保留 /NXCOMPAT;改造遗留动态代码先明确页权限设计。修改后重新启动目标程序,比较策略与执行型异常。
现场实施顺序
保留基线
导出有效策略及相关软件和驱动清单;标记系统构建、时间和变更单。先确认本地与集中管理是否会互相覆盖。
小范围验证
选择硬件和应用组合具有代表性的测试设备,按验证章节分别检查配置、运行和行为。只使用无害样本及测试数据。
分组推广
对审计发现逐项处理,再按机型、应用组合及业务窗口逐步扩大。监控启动失败、崩溃、认证失败和业务延迟等实际指标。
恢复与复测
通过原管理来源恢复明确的旧策略;涉及锁定或签名策略时遵循专用流程。重启或重启应用后重新验收,不以设置值变化作为恢复成功。
主要参考资料
以微软公开文档为主要依据,引用编号对应本册条目。技术推导、诊断顺序和演练方案属于运维设计;具体默认值和支持范围以目标构建及当前厂商资料为准。
[1] Data Execution Prevention
https://learn.microsoft.com/en-us/windows/win32/memory/data-execution-prevention
[2] PROCESS\_MITIGATION\_DEP\_POLICY
https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-process\_mitigation\_dep\_policy
[3] Exploit protection reference
https://learn.microsoft.com/en-us/defender-endpoint/exploit-protection-reference
11 技术参考与术语速查
正文中的数字引用保留原版基础资料;D编号对应下列深化资料。架构推导、实验设计和诊断方法用于解释机制,不构成未公开内部接口的稳定承诺。
[D1] VirtualQuery
https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualquery
[D2] Memory protection constants
https://learn.microsoft.com/en-us/windows/win32/memory/memory-protection-constants
本册关键对象速查
| 术语或对象 | 使用时先确认 |
|---|---|
| MEMORY\_BASIC\_INFORMATION | 以完整区域和权限解释故障地址 |
| EXCEPTION\_RECORD | 区分读 写 执行及目标地址 |
| PE DllCharacteristics | 静态兼容属性,不替代页权限 |
| 进程 DEP policy | 查询实际进程,不只看注册表 |
| 指令与异常上下文 | 还原跳转来源与目标 |
独立使用检查
先检查适用架构和版本,再确认工具与权限。配置意图、实际运行、具体触发事件分开记录。源文件、符号和策略ID按版本固定;未知字段或失败查询保留原始错误。完成修复后复测目标功能与关联业务,并撤销临时例外。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论