首页
社区
课程
招聘
《Windows 10 Control Flow Guard Internals》 Reading Notes
发表于: 2021-4-30 17:24 9128

《Windows 10 Control Flow Guard Internals》 Reading Notes

erfze 活跃值
12
2021-4-30 17:24
9128

Wikipedia:

Control Flow Guard (CFG) was first released for Windows 8.1 Update 3 (KB3000850) in November 2014. Developers can add CFG to their programs by adding the /guard:cf linker flag before program linking in Visual Studio 2015 or newer.

As of Windows 10 Creators Update (Windows 10 version 1703), the Windows kernel is compiled with CFG.The Windows kernel uses Hyper-V to prevent malicious kernel code from overwriting the CFG bitmap.

CFG operates by creating a per-process bitmap, where a set bit indicates that the address is a valid destination. Before performing each indirect function call, the application checks if the destination address is in the bitmap. If the destination address is not in the bitmap, the program terminates.This makes it more difficult for an attacker to exploit a use-after-free by replacing an object's contents and then using an indirect function call to execute a payload.

Windows CFG是Control-Flow Integrity(CFI)的具体实现,该机制由Windows 8.1 Update 3 (KB3000850)开始引入,需编译器和操作系统相结合,目的在于防止不可靠间接调用。漏洞利用常常通过修改间接调用地址以劫持执行流,而CFG会于编译链接期间将程序所有间接调用地址记录在PE文件中,并在执行所有间接调用前增加校验,若间接调用地址被修改,则抛出异常。

环境:

使用如下代码进行编译及调试:

启用CFG:

修改"调试信息格式":

编译完成,dumpbin.exe /headers /loadconfig Project1.exe

可以看到CFG已启用。

系统若不支持CFG,则不对___guard_check_icall_fptr进行更新(如下为Windows 7 SP1 x86):

若系统支持CFG,首先是nt!PspPrepareSystemDllInitBlock(由nt!NtCreateUserProcess—>nt!PspAllocateProcess—>nt!PspSetupUserProcessAddressSpace调用)初始化ntdll!LdrSystemDllInitBlock

其偏移0x60为Bitmap Address,0x68为Bitmap Size。

载入PE文件时,ntdll!LdrpCfgProcessLoadConfig会校验OptionalHeader.DllCharacteristics

修改_guard_check_icall_nop指向ntdll!LdrpValidateUserCallTarget

间接调用地址传递给ECX寄存器:

下面来看ntdll!LdrpValidateUserCallTarget校验过程:

注:

shr eax, 3 即Destination Address/8,Bitmap中每1bit对应进程空间8 Bytes。bt指令功能如下:

由于SRC寄存器是32位,故POSITION值需模32(0x20—0010 0000),如此一来,便做到取Destination Address最低字节前5位为索引。若Destination Address合法,则直接retn,非法会交由ntdll!RtlpHandleInvalidUserCallTarget,最终触发int 29中断。

在执行mov edx,dword ptr [edx+eax*4]时,若EAX寄存器已被篡改,则可能会触发内存访问异常,而ntdll!LdrpValidateUserCallTarget中并未加入异常处理,其异常处理位于ntdll!RtlDispatchException中:

最后交由ntdll!RtlpHandleInvalidUserCallTarget来处理:

nt!MiInitializeCfg首先调用nt!PsIsSystemWideMitigationOptionSet校验注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Kernel\MitigationOptions键值:

nt!PsIsSystemWideMitigationOptionSet函数返回零,则调用MmCreateSection

Section Object Address保存于nt!MiState+0x604处,InputMaximumSize为0x3000000。

nt!MiCfgInitializeProcess会调用nt!MiReferenceCfgVad向0xC0802174处写入_MI_CFG_BITMAP_INFO

 
 
typedef int(*fun_t)(int);
 
int foo(int a)
{
    printf("hellow world %d\n",a);
    return a;
}
class CTargetObject
{
public:
    fun_t fun;
};
int main()
{
    int i = 0;
    CTargetObject *o_array = new CTargetObject[5];
    for (i = 0; i < 5 ; i++)
        o_array[i].fun = foo;
    o_array[0].fun(1); 
    return 0;
}
typedef int(*fun_t)(int);
 
int foo(int a)
{
    printf("hellow world %d\n",a);
    return a;
}
class CTargetObject
{
public:
    fun_t fun;
};
int main()
{
    int i = 0;
    CTargetObject *o_array = new CTargetObject[5];
    for (i = 0; i < 5 ; i++)
        o_array[i].fun = foo;
    o_array[0].fun(1); 

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (2)
雪    币: 3736
活跃值: (3867)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
感谢分享!
2021-4-30 19:11
0
雪    币: 14488
活跃值: (17488)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2021-4-30 22:59
0
游客
登录 | 注册 方可回帖
返回
//