简介
Control Flow Guard(CFG)是较新的windows漏洞利用缓解措施,旨在解决内存损坏漏洞。 针对的是间接跳转的保护,比如call eax,jmp eax等。 CFG扩展了先前的漏洞缓解技术,例如GS,DEP和ASLR。
这个保护措施从Microsoft Visual Studio 2015及以上开始支持。
系统的话是从windows 8.1开始吧
简单来说就是在call eax等间接跳转之前加个验证。
实践
使用的示例代码
1 | typedef int(*fun_t)(int); |
修改编译选项
上面改了可能报错:
命令行 error D8016: “/ZI”和“/guard:cf”命令行选项不兼容
就是CFG与这个ZI不兼容,所以我们得关闭ZI
编译完成我们可以使用winchecksec工具查看是否开启了CFG
https://github.com/trailofbits/winchecksec
或者使用VS自带的工具dumpbin.exe,命令如下:
1 | dumpbin.exe /headers /loadconfig E:\VS2017\learnCFG\Debug\learnCFG.exe |
开启了CFG,OPTIONAL HEADER VALUES里面应该有Control Flow Guard
Section contains the following load config那里有“CF Instrumented”和“FID table present”等
我们看看开了CFG和没有开的区别
首先是没开的
接下来是开了的
双击跟过去那个检查函数是没有代码的,这应该是运行程序的时候再填充了
运行时,实际调用的是下面的ntdll!LdrpValidateUserCallTarget
原理分析
首先说说CFGBitmap
pCFG检查基于CFGBitmap,它表示在进程空间内所有函数的起始位置。在进程空间内每8个字节的状态对应CFGBitmap中的一位。如果函数的地址是合法有效的,那么这个函数对应在CFGbitmap的位置会被设置位1,否则是0。 p p一个Bitmap的大小是4字节
下面以地址0x00b01030为例(这是先知参考文章的例子)
具体调试结果跟解析如下了:
1 | ntdll!LdrpValidateUserCallTarget: |
那么最终假如校验失败,那就会跳到
1 | 77408c3c e8e7460500 call ntdll!RtlpHandleInvalidUserCallTarget (7745d328) |
最终int 0x29抛出异常
参考
https://blog.trendmicro.com/trendlabs-security-intelligence/exploring-control-flow-guard-in-windows-10/
https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard
https://xz.aliyun.com/t/2587
https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard#how-do-i-tell-that-a-binary-is-under-control-flow-guard