控制流保护(CFG)是Windows我们可以用这个例子来分析一种安全机制,目的是检查间接调用的目标地址是否是减少执行流重定向的有效函数。
0x01 CFG如何工作
通过这个例子,我们使用它MSVC编译一个编译器exe文件,看调用main()之前生成和执行了什么代码:
随后执行:
_guard_check_icall_nop地址会被NT DLL中的Ldrp验证用户调用目标替换:
对于CFG,他们在Load Config目录中的PE 添加了一堆新字段Guard CF Check 函数 指 针 guard_check_icall_ptr,函数地址和Guard CF函数表,该表包含所有要设置为有效目标的函数的RVA,在加载PE时创建的Bitmap中。
验证用户调用目标Ldrp从第一个指令中LdrSystemDllInit块 0xb0获取Bitmap的地址。Bitmap每16个字节包含在整个过程中“状态”,当加载PE时,表中的RVAs将偏移量转换为偏移量,然后相应地设置偏移量的状态。
0x03 传送 Bitmap
我的想法是使用它Guard CFFunction表填充具有选定状态Bitmap,重生我们的代码,然后在入口点复制到Bitmap由于 Alex Ionescu 在WindowsInternals在研究中,我可以找到一些以前的文档:
假设我们代码中的第一个字节是0x10(010000b),我们从Bitmap从区域传输代码0x402000(RVA:0x2000)一开始,为了明确起见,我们将使用相同的区域来处理假货RVA。要生成 0x10,我们只需要表中的一个项目:0x2020,跳过前32个字节,将状态设置为0000b,0x2020将下一个状态设置为 01b,Bitmap变为010000b。现在得到状态11b,假设我们想要字节0x1D(011101b),我们使用未对齐的RVA,表将变成:0x2000(设置为01b),0x2012(设置为11b),0x2020(设置为01b)。
要获得10b,我们需要使用具有元数据的特殊类型 RVA,但很简单,我们在生成中添加了一个字节10b的 RVA 中 。
元数据是一个标志: IMAGE_GUARD_FLAG_FID_SUPPRESSED (1) 或
IMAGE_GUARD_FLAG_EXPORT_SUPPRESSED(2)0x86(10000110b),使用:0x2000与0x2(设置为10b),0x2010(设置为01b),0x2030与0x2(设置为10b)。
0x04 Bitmap 转换
0x05 分析总结
那么,当检测到无效地址时会发生什么呢? 程序终止了。因为大多数变化PE文件的工具或代码不支持CFG:必须在表中更改在其他地方执行代码的任何地址。这将杀死许多病毒改变入口地址或使用入口地址Fuzzing(EPO)技术效果。但是,如果是PE中禁用CFG,可以用自己的地址代替Guard CF Check获得函数指针EPO。
本文翻译自:https://github.com/86hh/PagedOut2/blob/master/CFGTeleport.pdf若转载,请注明原址: