让我们梳理下一RFG防护的基本思路:
1) 在每一个函数开始处,”读”取当前栈rsp里面的值到rax中,该值就是函数的返回地址,我们记作return_value
2) 然后将rax里面值”写”入fs:[rsp] 偏移处 , 也就是保留函数返回地址return__value的值到”影子栈“Thread Control stack当中。
3) 在函数即将结束的时候检测当前返回地址值return_value和fs:[rsp]中保存的是否一致,如果一致,函数正常返回,如果不一致将跳向
xxx!_guard_ss_verfiy_failure_rdx, 表明可能受到攻击者利用,进而会引发int29异常,进程崩溃,阻止漏洞利用的进行。
那么有哪些机制决定RFG开启功能呢?
1 内核里面的全局变量nt!MnEnableRfg用来决定系统是否开启支持RFG功能
2 针对具体进程的PE头部,PE.LoadConfigDirectory.GuardFlag标记用来决定该进程是否支持RFG功能
3 可以通过SetProcessMitigationPolicy来动态设定一个进程是否开启RFG功能。
关于RFG涉及到的很多细节大家可以参考腾讯玄武实验室的一篇blog:
http://xlab.tencent.com/cn/2016/11/02/return-flow-guard/
[0x02] 防护层面分析:
现在我们需要回答3个问题以及为什么这样会起到很强的保护作用。
1 fs可否被攻击者控制进而改写?
2 fs对应的影子栈指向何处?
3 如何保证fs指向的“影子栈”位置是随机的,可以不被攻击者预测到?
下面我将从用户层和内核层面来分析这个3个问题。
[0x02.1] 用户层面的分析
首先,在用户层面fs值本身是不可被改写(换句话说,特殊的方式下需要可利用的漏洞具有相当的便利性才有可能,存在fs被清空为0的可能,此时2个栈重合,防御失效),也就不存攻击者可以通过修改fs寄存器的值来
伪造出“影子栈”的内容,绕过上面提到的步骤3的验证。
因为用户层面,fs选择子的值不具有意义,例如下面的fs寄存器的值,见下面代码
0:018> r
rax=00007ffd5bb757b5 rbx=0000023b69a2cea0 rcx=0000023b69a2cea0
rdx=00007ffd5c09dff8 rsi=0000007311dfb730 rdi=0000023b69a2cea0
rip=00007ffd5bb3d250 rsp=0000007311dfb588 rbp=0000023b6a736050
r8=0000007311dfb600 r9=0000023b5092ce50 r10=00000fffab76eaf2
r11=0000007311dfb5c8 r12=fffc000000000000 r13=0000000000000124
r14=0000023b50943040 r15=0000023b6a736050
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
chakra!Js::ExternalObject::IsObjectAlive+0x4:
00007ffd`5bb3d250 6448890424 mov qword ptr fs:[rsp],rax fs:00000073`11dfb588=00007ffd5bb757b5
这里的fs=53 不具有操作上的含义,53是选择子,你可以任意修改它为其它任何值,不影响程序的运行(在x86下是不可以被修改的)。同样我们
也不能在调试器通过dg命令表来获得fs真正含义。
0:018> dg fs
P Si Gr Pr Lo
Sel Base Limit Type l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0053 00000000`10181000 00000000`00000fff Data RW Ac 3 Bg By P Nl 000004f3
也就是说上面的00000000`10181000并不是fs所指向的真正的基地址,在我调试的环境下总是指向一个未被映射的地址空间。
0:018> !address 00000000`10181000
Usage: Free
Base Address: 00000000`00000000
End Address: 00000000`7ffe0000
Region Size: 00000000`7ffe0000 ( 2.000 GB)
State: 00010000 MEM_FREE
Protect: 00000001 PAGE_NOACCESS
Type: <info not present at the target>
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。