Windows 安全机制---GS
一;GS基本原理
GS功能是Windows 针对栈溢出而产生得防御技术。其主要原理是在调用函数初始化一个栈帧之后将一个随机数放入栈当中,并且在“.data“节区保存一个副本。每次在执行返回地址得指令之前都需要验证一下随机值。如果发生变化,则认为产生溢出。接下来,我们通过对比看看启动GS前后栈空间得变化。
测试环境:
|
|
|
操作系统 |
Windows 家庭版 |
|
编程环境 |
VS 2019
|
|
测试代码:
#include
#include
#include
#pragma strict_gs_check(on)
int vul(const char * str) {
char arry[8];
strcpy_s(arry,str);
return 1;
}
int main() {
__asm int 3
const char* str = "qqqq";
int c = vul(str);
return 0;
}
注释:如何启动关闭GS功能如下图:

我们设定好之后,直接编译,发现代码在“__asm int 3”的位置断下来,接着我们查看“反汇编”窗口,如下代码。我们知道在断点之后的代码首先将字符串“qqqq”放入内存并且将对应的地址放入寄存器EAX当中压入栈。
008518AE int 3
008518AF mov dword ptr [str],offset string "qqqq" (0857B30h)
16: const char* str = "qqqq";
17: int c = vul(str);
008518B6 mov eax,dword ptr [str]
008518B9 push eax
008518BA call vul (085139Dh)
我们步入进入函数vul()查看。如下汇编指令:
008517C0 push ebp
008517C1 mov ebp,esp
008517C3 sub esp,0D4h
008517C9 push ebx
008517CA push esi
008517CB push edi
008517CC lea edi,[ebp-0D4h]
008517D2 mov ecx,35h
008517D7 mov eax,0CCCCCCCCh
008517DC rep stos dword ptr es:[edi]
008517DE mov eax,dword ptr [__security_cookie (085A004h)] //初始cookie值
008517E3 xor eax,ebp //初始cookie值与当前栈EBP的值进行异或
008517E5 mov dword ptr [ebp-4],eax //将异或后的值放入栈空间
008517E8 mov ecx,offset _43DCD8FE_test@cpp (085C009h)
008517ED call @__CheckForDebuggerJustMyCode@4 (085130Ch)
9: char arry[8];
10: strcpy_s(arry, str);
008517F2 mov eax,dword ptr [str]
008517F5 push eax
008517F6 lea ecx,[arry]
008517F9 push ecx
008517FA call strcpy_s<8> (08512D5h)
008517FF add esp,8
11: return 1;
00851802 mov eax,1
12: }
00851807 push edx
00851808 mov ecx,ebp
0085180A push eax
0085180B lea edx,ds:[851838h]
00851811 call @_RTC_CheckStackVars@8 (08511D1h)
00851816 pop eax
00851817 pop edx
00851818 pop edi
00851819 pop esi
0085181A pop ebx
0085181B mov ecx,dword ptr [ebp-4] //取出cookie值
0085181E xor ecx,ebp //异或处理
00851820 call @__security_check_cookie@4 (085113Bh) //调用验证函数
00851825 add esp,0D4h
0085182B cmp ebp,esp
0085182D call __RTC_CheckEsp (0851230h)
00851832 mov esp,ebp
00851834 pop ebp
00851835 ret
由上述代码,我们首先将vul() 函数分配得栈空间画出来,详细如下图:
注释:这里因为vul() 函数当中同样调用了strcpy_s()函数,所以同样会有对strcpy_s()函数得栈空间,这里不去讨论。

1.1;security_cookie值得产生
我们看到,在正常进行初始化一个栈空间的程序当中,插入了如下代码。由代码我们可以知道,首先会有一个初始的security_cookie值放入寄存器。
008517DE mov eax,dword ptr [__security_cookie (085A004h)]
008517E3 xor eax,ebp
008517E5 mov dword ptr [ebp-4],eax
通过使用工具,我们发现初始值得地址在节区“.data”范围。详细如下图:

1.2;security_cookie值的验证
我们知道,在vul()函数返回得时候,会执行针对security_cookie得验证,接下来,我们来看看如下代码。首先将放入[ebp-4]位置得security_cookie值取出并且再次与当前得栈EBP值进行异或,并且将值放入ECX当中,之后调用验证函数。
0085181B mov ecx,dword ptr [ebp-4]
0085181E xor ecx,ebp
00851820 call @__security_check_cookie@4 (085113Bh)
接下来,我们步入验证函数,看看操作了什么,这里我们看如下代码,我们发现它将ECX,与“085a004h”地址得值进行对比。对比相同则执行ret指令,即跳转会之前vul()得栈空间,如果不相同值跳转到“0851b4bh”。这里我们注意地址“085a004h”得值就是初始得security_cookie。
00851B40 cmp ecx,dword ptr [__security_cookie (085A004h)]
00851B46 bnd jne failure (0851B4Bh)
00851B49 bnd ret
总结:
在正常执行完初始化一个栈帧结束之后,会执行将“.data”节的第一个双字作为初始化cookie(具备随机性)。
然后使用初始化的种子cookie种子与当前的栈EBP进行异或运算,将值放入栈[ebp-4]的位置当中。
在函数返回之前,即执行ret指令之前,调用验证函数进行验证。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2021-4-8 17:17
被天象独行编辑
,原因: