控制平台安全性Flow防护

什么是控制Flow防护?

控制Flow防护 (CFG) 是一项高度优化的平台安全功能,旨在打击内存损坏漏洞。 通过严格限制应用程序可以从何处执行代码,利用漏洞(如缓冲区溢出)执行任意代码会更加困难。 CFG 扩展了以前的攻击缓解技术,如 /GSDEPASLR

  • 防止内存损坏和勒索软件攻击。
  • 将服务器的功能限制为在特定时间点所需的任何功能,以减少攻击面。
  • 更难通过缓冲区溢出等漏洞利用任意代码。

此功能在 2015 Microsoft Visual Studio中提供,并在Windows的“CFG 感知”版本上运行,即适用于桌面和 Windows 10服务器的 x86 和 x64 版本,Windows 8.1 更新 (KB3000850) 。

我们强烈建议开发人员为其应用程序启用 CFG。 无需为代码的每个部分启用 CFG,因为已启用 CFG 的非 CFG 代码将执行罚款。 但是,未能为所有代码启用 CFG 可能会打开保护中的空白。 此外,已启用 CFG 的代码适用于Windows的“CFG-Unaware”版本,因此与它们完全兼容。

如何启用 CFG?

在大多数情况下,无需更改源代码。 只需向 Visual Studio 2015 项目添加一个选项,编译器和链接器将启用 CFG。

最简单的方法是导航到Project |属性|配置属性|C/C++ |代码生成并选择“是”, (/guard:cf) 控制Flow防护。

cfg property in visual studio

或者,将 /guard:cf 添加到 Project |属性|配置属性|C/C++ |命令行| 编译器) 和 /guard:cf Project | 的其他选项 (属性|配置属性|链接器|命令行| 链接器) 的其他选项 (。

cfg property for compilercfg property for linker

有关其他信息,请参阅 /guard (启用控制Flow防护)

如果要从命令行生成项目,可以添加相同的选项。 例如,如果要编译名为 test.cpp 的项目,请使用 cl /guard:cf test.cpp /link /guard:cf

还可以选择使用内存管理 API 中的 SetProcessValidCallTargets 动态控制 CFG 视为有效的 icall 目标地址集。 可以使用同一 API 来指定页面是无效还是有效的 CFG 目标。 VirtualProtectVirtualAlloc 函数默认将指定的可执行文件和提交的页面区域视为有效的间接调用目标。 可以通过指定在调用 VirtualAlloc 时或 PAGE_TARGETS_NO_UPDATE调用VirtualProtect 时按内存保护常量下详述的方式指定PAGE_TARGETS_INVALID来替代此行为,例如在实现实时编译器时。

如何判断二进制文件处于控制Flow防护之下?

使用 /headers/loadconfig 选项从 Visual Studio 命令提示符运行 Visual Studio 2015 安装) 中包含的转储绑定 (工具dumpbin /headers /loadconfig test.exe。 CFG 下的二进制文件的输出应显示标头值包括“Guard”,并且加载配置值包括“CF 检测”和“FID 表存在”。

output from dumpbin /headers

output from dumpbin /loadconfig

CFG 如何真正工作?

软件漏洞通常通过向正在运行的程序提供不太可能、异常或极端的数据来利用。 例如,攻击者可以通过向程序提供比预期更多的输入来利用缓冲区溢出漏洞,从而过度运行程序保留的区域来保存响应。 这可能会损坏可能保存函数指针的相邻内存。 当程序通过此函数调用时,它可能会跳转到攻击者指定的意外位置。

但是,CFG 的编译和运行时支持的有效组合实现了控制流完整性,严格限制间接调用指令可以执行的位置。

编译器执行以下操作:

  1. 将轻型安全检查添加到已编译的代码。
  2. 标识应用程序中用于间接调用的有效目标的函数集。

Windows内核提供的运行时支持:

  1. 有效维护标识有效间接调用目标的状态。
  2. 实现验证间接调用目标的逻辑是否有效。

为了说明:

cfg pseudocode

当 CFG 检查在运行时失败时,Windows会立即终止程序,从而破坏尝试间接调用无效地址的任何攻击。