/GS(缓冲区安全检查)浅析
来源:互联网 发布:网络鲜花礼品网 编辑:程序博客网 时间:2024/04/30 14:41
VC.net 增加了/GS缓冲区安全检查编译选项。MSDN是这样说明的:检测某些覆盖函数返回地址、异常处理程序地址或特定类型的参数的缓冲区溢出。导致缓冲区溢出是黑客用于利用不强制缓冲区大小限制的代码的一种技术。
安全检查
对于编译器认为容易出现缓冲区溢出问题的函数,编译器将在堆栈上返回地址之前分配空间。在进入函数时,用安全 Cookie(它在模块加载时计算一次)加载分配的空间。在退出函数时,以及在 64 位操作系统上展开帧的过程中,将调用 helper 函数,以确保 Cookie 值仍保持不变。不同的值指示可能已覆盖堆栈。如果检测到不同的值,则终止该进程。
GS 缓冲区生成依赖项只指在解决方案中的项目依赖项。GS 缓冲区可以是下列之一:
1、In earlier versions of $$$$, this level of dependency was sufficient.
2、大小大于 8 字节且不包含指针的数据结构。
3、通过使用 _alloca 函数分配的缓冲区。
4、包含 GS 缓冲区的任何类或结构。
以下实战:
开了/GS编译开关,每个入口函数都要进行初始化检测值。
.text:00012606 ; NTSTATUS __stdcall DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
.text:00012606 public DriverEntry
.text:00012606 DriverEntry proc near
.text:00012606
.text:00012606 DriverObject = dword ptr 8
.text:00012606 RegistryPath = dword ptr 0Ch
.text:00012606
.text:00012606 mov edi, edi
.text:00012608 push ebp
.text:00012609 mov ebp, esp
.text:0001260B call InitCookie ; 初始化/GS编译开关的堆栈溢出Cookie
.text:00012610 pop ebp
.text:00012611 jmp sub_12530
.text:00012611 DriverEntry endp
INIT:0001715F ; 初始化/GS编译开关的堆栈溢出Cookie
INIT:0001715F
INIT:0001715F InitCookie proc near ; CODE XREF: DriverEntry+5 p
INIT:0001715F mov eax, dwCheckValue
INIT:00017164 mov ecx, 0BB40E64Eh
INIT:00017169 test eax, eax
INIT:0001716B jz short loc_17171
INIT:0001716D cmp eax, ecx
INIT:0001716F jnz short loc_1718B
INIT:00017171
INIT:00017171 loc_17171: ; CODE XREF: InitCookie+C j
INIT:00017171 mov eax, ds:KeTickCount
INIT:00017176 mov eax, [eax]
INIT:00017178 xor eax, offset dwCheckValue
INIT:0001717D mov dwCheckValue, eax
INIT:00017182 jnz short loc_1718B
INIT:00017184 mov eax, ecx
INIT:00017186 mov dwCheckValue, eax
INIT:0001718B
INIT:0001718B loc_1718B: ; CODE XREF: InitCookie+10 j
INIT:0001718B ; InitCookie+23 j
INIT:0001718B not eax
INIT:0001718D mov dwCookie, eax
INIT:00017192 retn
dwCookie 存放堆栈检测标志数值,dwCheckValue 后面用于测试使用.
下面是/GS编译开关的效果函数(中间省略掉一堆无关操作代码)
PAGE:00015C30 ; =============== S U B R O U T I N E =======================================
PAGE:00015C30
PAGE:00015C30 ; Attributes: bp-based frame
PAGE:00015C30
PAGE:00015C30 sub_15C30 proc near ; CODE XREF: sub_12394+77 p
PAGE:00015C30 ; sub_15AA2+22 p
PAGE:00015C30
PAGE:00015C30 var_5C = dword ptr -5Ch // 这次变量够多了吧............................
PAGE:00015C30 var_58 = dword ptr -58h
PAGE:00015C30 var_48 = dword ptr -48h
PAGE:00015C30 var_44 = dword ptr -44h
PAGE:00015C30 var_40 = byte ptr -40h
PAGE:00015C30 var_3C = dword ptr -3Ch
PAGE:00015C30 var_38 = dword ptr -38h
PAGE:00015C30 var_34 = dword ptr -34h
PAGE:00015C30 var_30 = dword ptr -30h
PAGE:00015C30 var_2C = dword ptr -2Ch
PAGE:00015C30 var_28 = dword ptr -28h
PAGE:00015C30 var_24 = dword ptr -24h
PAGE:00015C30 var_20 = dword ptr -20h
PAGE:00015C30 var_1C = dword ptr -1Ch
PAGE:00015C30 P = dword ptr -18h
PAGE:00015C30 var_14 = dword ptr -14h
PAGE:00015C30 var_D = byte ptr -0Dh
PAGE:00015C30 var_C = byte ptr -0Ch
PAGE:00015C30 var_B = byte ptr -0Bh
PAGE:00015C30 var_A = word ptr -0Ah
PAGE:00015C30 var_8 = word ptr -8
PAGE:00015C30 var_6 = word ptr -6
PAGE:00015C30 var_4 = dword ptr -4 // 堆栈顶部变量值
PAGE:00015C30 arg_0 = dword ptr 8
PAGE:00015C30
PAGE:00015C30 mov edi, edi
PAGE:00015C32 push ebp
PAGE:00015C33 mov ebp, esp
PAGE:00015C35 sub esp, 5Ch
PAGE:00015C38 mov eax, dwCheckValue
PAGE:00015C3D xor eax, ebp
PAGE:00015C3F mov [ebp+var_4], eax // 将检测值放入堆栈顶部
// 在中间,函数进行一些操作
....................................................... // 函数进行一些操作
// 执行到函数的结尾了
PAGE:00015F8C mov ecx, [ebp+var_4] // 取出本地堆栈顶部
PAGE:00015F8F mov eax, edi
PAGE:00015F91 pop edi
PAGE:00015F92 pop esi
PAGE:00015F93 xor ecx, ebp
PAGE:00015F95 pop ebx
PAGE:00015F96 call loc_1247D // 进程检测堆栈是否被覆盖了(检测数值被更改了)
PAGE:00015F9B leave
PAGE:00015F9C retn 4
PAGE:00015F9C sub_15C30 endp
call loc_1247D 代码如下:
.text:0001247D loc_1247D: ; CODE XREF: sub_11352+37E p
.text:0001247D ; sub_15C30+366 p
.text:0001247D cmp ecx, dwCheckValue // 检测堆栈顶部是否相等(也就是没有被覆盖刚才那个var_4栈顶变量)
.text:00012483 jnz short loc_12488 // 如果不等,则调用KeBugCheckEx打印出堆栈检测更改数值与原始数值,并蓝屏
.text:00012485 retn 0
.text:00012488 ; ---------------------------------------------------------------------------
.text:00012488
.text:00012488 loc_12488: ; CODE XREF: .text:00012483 j
.text:00012488 jmp loc_12492
.text:00012488 ; ---------------------------------------------------------------------------
.text:0001248D db 5 dup(0CCh)
.text:00012492 ; ---------------------------------------------------------------------------
.text:00012492
.text:00012492 loc_12492: ; CODE XREF: .text:loc_12488 j
.text:00012492 mov edi, edi
.text:00012494 push ebp
.text:00012495 mov ebp, esp
.text:00012497 push ecx
.text:00012498 mov [ebp-4], ecx
.text:0001249B push 0
.text:0001249D push dwCookie
.text:000124A3 push dwCheckValue
.text:000124A9 push dword ptr [ebp-4]
.text:000124AC push 0F7h
.text:000124B1 call ds:KeBugCheckEx
在所有平台上,/GS 尝试检测进入返回地址的缓冲区溢出。通过调用约定将函数调用的返回地址存储到堆栈上,可以更容易地在平台(如 x86 和 x64)上利用缓冲区溢出。在 x86 上,如果函数使用异常处理程序,则编译器将插入一个安全 Cookie 以保护异常处理程序的地址。在展开帧的过程中会检查该 Cookie。
- /GS(缓冲区安全检查)浅析
- 缓冲区安全检查
- 缓冲区溢出GS
- 初探VS2010缓冲区安全检查
- OpenJDK类加载实现浅析#2:安全检查
- gs
- gs
- [翻译]用/GS选项开关防范缓冲区溢出漏洞
- VC++中利用/GS开关防止缓冲区溢出
- 在Visual C++中利用/GS开关防止缓冲区溢出
- VC++中利用/GS开关防止缓冲区溢出
- 在Visual C++中利用/GS开关防止缓冲区溢出
- VC++中利用/GS开关防止缓冲区溢出
- 浅析IO缓冲区
- 浅析缓冲区溢出
- IIS安全检查清单(中英对照)
- 浅析标准I/O缓冲区
- 浅析标准I/O缓冲区
- C++中的格式控制
- 爱,有你才完整-----by 魏晨
- {linux程序}之网络程序的并发之路
- 光线补足 直方图均衡化 弧形灰度拉伸
- 泪光翅膀----by蓝正龙
- /GS(缓冲区安全检查)浅析
- onActivityResult 方法学习 和 遇见的问题
- Trouble maker
- hdu 1076 An Easy Task
- 简单的跟踪示例代码
- win8 64位操作系统安装Oracle11g 并配置PLSQL
- IO - 同步,异步,阻塞,非阻塞
- struts2的自定义方法与输入校验
- 写在JEECG 3.0发布之前