关于CFG的研究

关于CFG的研究

CFG(Control Flow Guard)控制流防护,是微软在Windows8.0以及Windows10上推出的新的防护机制

防护点在于,防护间接调用,防止在程序间接调用函数的时候,使用恶意代码进行替换,导致执行恶意程序。CFG的实现机制在于每当存在间接调用的函数的时候,就会先去判断一下间接调用的地址处是不是一个有效的函数的起始地址。主要关注缓解间接调用和调用不可靠目标的问题(在没有CFG支持的Windows中,这个函数不做任何事。在Windows 10中,有了CFG的支持,它指向ntdll!LdrpValidateUserCallTarget函数)

加了CFG和不加CFG的程序,反汇编的对比

在这里插入图片描述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P3HlN88M-1617420281471)(C:\Users\Administrator\Desktop\CFG研究\typora-user-images\image-20200722175329986.png)]
通过对比二者反汇编结果可以明显的看出加了CFG防护机制的程序,会在调用之前,调用_guard_check_icall_fptr函数,该函数的功能其实就是对目标偏移进行校验,检查其是否是一个有效的函数起始地址
注意:给程序添加CFG防护只需要在编译生成的时候,添加选项就好,如下图所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VZrus3uQ-1617420281475)(C:\Users\Administrator\Desktop\CFG研究\typora-user-images\image-20200722194534610.png)]
另外,还有一点需要注意,就是在生成的时候,要把编译器的优化选项关闭掉,否则生成的代码通过IDA反编译的结构也是看不到CFG守护函数的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ove1P0DA-1617420281481)(C:\Users\Administrator\Desktop\CFG研究\typora-user-images\image-20200722194716222.png)]
添加CFG防护之后,检测具体有没有添加,可以使用VS自带的工具dumpbin.exe 执行命令

dumpbin.exe /headers /loadconfig C:\Users\Administrator\source\repos\LoadDestDLL\Release\LoadDestDLL.exe

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
Guard CF address of check-function pointer:该函数地址指向函数_guard_check_icall_fptr

动态调试,Windbg动态调试EXE文件方法(断到入口点的方法)

1:加载符号,设置符号路径

2:File->OpenProcess

3:打开文件之后,停在Ntdll.dll模块里边,这个时候,可以使用lm命令来查看,当前进程的一些起始信息:

在这里插入图片描述

之后可以使用 以下命令来解析PE文件

!dh -a(-f) 目标模块的文件名

获取到入口点地址之后,加基址下断点:
在这里插入图片描述
下bp断点,之后执行就会断到入口点,但是需要注意入口点 不是main函数的入口点,这个直接在IDA里边看到之后,修改基址跳过去下断点就好了

到达目标函数之后,单步步进:
在这里插入图片描述
步进之后:整个CFG的处理过程(这里需要注意,在调试的时候选取支持CFG机制的Windows版本才会存在相应的代码块,否则什么也不做直接返回)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
操作系统在创建支持CFG机制的进程的时候,将CFGbitmap映射到该进程的地址空间中,同时将基址保存在ntdll!LdrSystemDllInitBlock+0xb0里边
(绿盟发表的文章里边,这个位置的基址存储位置是ntdll!LdrSystemDllInitBlock+0x60,但是我在实际调试的过程中,看到的是0xb0),但是在Windows Internal的文章里边标明确实是0x60
在这里插入图片描述
Windows Internal里关于该结构的描述:
在这里插入图片描述
在这里插入图片描述
CFG进行校验的方式:

CFG进行校验主要依靠一个CFGBitmap的数据,而这个数据的来源就是我们在开启了CFG防护机制的时候,会将所有间接调用的函数形成一个CFG Function Table的结构,而这个函数数据表以BitMap的方式存储在CFGBitmap里边,以供接下来的函数地址验证.操作喜用在加载支持CFG的进程的时候,根据其Guard CF Function Table来更新CFG Bitmap中该模块所对应的位。同时,将函数指针_guard_check_icall_fptr初始化为指向ntdll!LdrpValidateUserCallTarget。

BitMap的原理:

例如:定义一个int类型的数据的时候,int数据类型在内存中占4个字节的空间也就是32bit,当定义一个拥有32个int元素的数组的时候,实际占用内存空间:32*32bit,但是其实,当int类型数据的字节码的每一位都代表一个数字的话,32个数字只需要32位的空间就可以存储,如下图所示:
在这里插入图片描述
CFGBitmap的逻辑也是类似于这样的。

整个CFG的校验过程:

1 、取目标地址的高24位作为索引

2 、将CFGBitmap当作一个32bit的数组,用刚才得到的索引值,在这个数组里取出一个32位的整数bits(其实就是去索引的过程)

3 、取刚才获得到的32位整数bits的第4-8位(3-7)作为偏移量n(定位到具体的目标地址)

4 、判断目标地址是否以0x10对齐,如果不是则设置n的最低位(判断偏移量)

5、 取32位整数bits的第n位即为目标地址的对应位(确定目标地址)

具体验证过程:

第一步:取目标地址的高24位

shr eax,8右移8位,相当于取高4个字节

edx,dword ptr [edx+eax*4]取目标地址高24位作为32位数组的索引,取出32位的整数bits,获取到的索引如下图所示
在这里插入图片描述
第二步:

shr eax,3目标地址右移3位

eax = ecx = 0xf11080   ->   eax  >> 3 = 0x1e2210
test cl ,0Fh    //   0xa0  &  0x0F  = 0  
ZF = 0           // ZF 为0 ,jne不跳转,说明以0x0f对齐
bt edx, eax 	//这个过程的主要目的就是取出低位的第3-7位数据作为偏移量n
				//bt 指令把指定的位传送给CF标志寄存器,这里的意思就是把 edx 的某一位放到CF里,这个某一位由eax的值确定,那eax的值呢?就是 eax mod 32                 //的值,至于位什么取余32,是依靠目的寄存器的位数的来决定的,edx是32位寄存器,所以就对32取余。为什么对32取余可以得到第3-7位数据?在之前右移3位之后,处在数据末尾的就剩最后一个字节的第3-7位,这5位加起来是31,正好够对32取余

整个验证过程如上,执行bt指令之后,如果目标间接调用地址是合法的函数地址(也就是说在CFGBitmap里边存在这个函数),那么就会将cf位 置1,否则就不会将CF置位(但是其实在第一次检测没有通过的时候,系统会将eax最后一位置位,再重新检测一次)
在这里插入图片描述
当不以0x10对齐的时候,执行以下分支:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NktmXmCN-1617420281513)(C:\Users\Administrator\Desktop\CFG研究\typora-user-images\image-20200724153053946.png)]

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值