浅谈缓冲区溢出检查_security_cookie

介绍:

当应用程序启动时,程序的cookie(4字节(dword),无符号整型)被计算出来(伪随机数)并保存在

加载模块的.data节中,在函数的开头这个cookie被拷贝到栈中,位于EBP和返回地址的正前方(位于返

回地址和局部变量的中间)。

 

[buffer][cookie][savedEBP][savedEIP]

在函数的结尾处,程序会把这个cookie和保存在.data节中的cookie进行比较。

如果不相等,就说明进程栈被破坏,进程被终止。

  

在典型的缓冲区溢出中,栈上的返回地址会被数据所覆盖,但在返回地址被覆盖之前,cookie早已经被

覆盖了,因此在函数的结尾程序会发现cookie已经被破坏,接着应用程序会被结束。


实践:

VC编译器启用Buffer Security Check时,会在有字符串操作的函数处加入_security_cookie,也就是用来检查缓冲区溢出

如下图的配置,默认是打开的:


接下来我们看下,在有字符串等缓冲区操作的函数,编译器会添加什么代码来检查:

首先在函数入口处:

00401050 83ec10          sub     esp,10h
00401053 a100a04100      mov     eax,dword ptr [CSWinMain1!__security_cookie (0041a000)]
00401058 33c4            xor     eax,esp
0040105a 8944240c        mov     dword ptr [esp+0Ch],eax
0040105e 6a0c            push    0Ch
取出__security_cookie, xor esp 放在当前esp+0ch处


在函数返回时有如下代码:

0040109c 8b4c2428        mov     ecx,dword ptr [esp+28h]
004010a0 83c41c          add     esp,1Ch
004010a3 33cc            xor     ecx,esp
004010a5 e862010000      call    CSWinMain1!__security_check_cookie (0040120c)

由于esp在中间操作过,所以这里esp+28h就是之前存放cookie值的,取出来,然后 xor回去;


call    CSWinMain1!__security_check_cookie (0040120c)
在进去看到如下代码:

CSWinMain1!__security_check_cookie:
0040120c 3b0d00a04100    cmp     ecx,dword ptr [CSWinMain1!__security_cookie (0041a000)]
00401212 7502            jne     CSWinMain1!__security_check_cookie+0xa (00401216)
00401214 f3c3            rep ret
00401216 e981150000      jmp     CSWinMain1!__report_gsfailure (0040279c)
这里看到这个ecx值和原始存放的值进行了比较,如果不相等,则跳到__report_gsfailure.

如果要更详细的了解实现,也可以查看相关的源码在:

X:\Program Files\Microsoft Visual Studio 8\VC\crt\src\gs_report.c

X:\Program Files\Microsoft Visual Studio 8\VC\crt\src\gs_cookie.c

那么使用这个的好处大家应该可以看到了,具体我们来看下_security_cookie有或无时crash的 dump;

没用_security_cookie

STACK_TEXT:  
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012ff38 41414141 00414141 005c1b70 005c1bc0 0x41414141
0012ff88 76baed6c 7ffdb000 0012ffd4 772337eb 0x41414141
0012ff94 772337eb 7ffdb000 77bc2d38 00000000 kernel32!BaseThreadInitThunk+0xe
0012ffd4 772337be 00401449 7ffdb000 00000000 ntdll!__RtlUserThreadStart+0x70
0012ffec 00000000 00401449 7ffdb000 00000000 ntdll!_RtlUserThreadStart+0x1b

这个stack已经乱了,其实0x41414141这个地址就是被溢出时的字符串,这么看就比较难定位原因了;

用了_security_cookie

0012fbec 0040287b 00417264 834f4bdb 7cb0b424 kernel32!UnhandledExceptionFilter+0x5f
0012ff20 004010aa 64636261 6766652b 6c6b6a68 CSWinMain1!__report_gsfailure+0xdf [f:\dd\vctools\crt_bld\self_x86\crt\src\gs_report.c @ 313]
0012ff88 76baed6c 7ffd6000 0012ffd4 772337eb CSWinMain1!Test1+0x5a [e:\projects\cswinmain1\cswinmain1.cpp @ 36]
0012ff88 76baed6c 7ffd6000 0012ffd4 772337eb kernel32!BaseThreadInitThunk+0xe
0012ff94 772337eb 7ffd6000 7754c743 00000000 kernel32!BaseThreadInitThunk+0xe
0012ffd4 772337be 00401468 7ffd6000 00000000 ntdll!__RtlUserThreadStart+0x70
0012ffec 00000000 00401468 7ffd6000 00000000 ntdll!_RtlUserThreadStart+0x1b
通过stack,可以看到具体错误的函数,返回地址不会因此而变成未知地址,可以确定错误原因就在那个Test1函数某处字符串操作的地方。








### OllyDbg 中 CALL 指令未显示地址的原因分析 在使用 OllyDbg 反汇编时,某些情况下可能会发现 `CALL` 指令后并未直接显示目标地址,而是以符号形式(如 `__security_init_cookie`)呈现。这种现象通常与以下几个因素有关: #### 1. **符号解析机制** OllyDbg 在加载程序时会尝试解析符号表,并将已知的函数名称映射到对应的地址上[^1]。如果目标程序包含调试信息(如 PDB 文件),或者动态链接库(DLL)中已经定义了符号表,那么 OllyDbg 将优先显示符号名而非具体地址。因此,当看到 `CALL hollo.__security_init_cookie` 时,实际上是 OllyDbg 已经成功解析了该函数的符号。 #### 2. **安全 cookie 初始化机制** `__security_init_cookie` 是微软编译器为防止缓冲区溢出攻击而引入的一种安全机制。它会在程序启动时生成一个随机值(即安全 cookie),并将其存储在特定内存位置。此函数的调用通常出现在程序初始化阶段,用于确保栈保护功能正常工作[^2]。由于这是一个常见的系统函数,其符号可能已被预定义,因此在反汇编视图中仅显示符号名。 #### 3. **间接调用与延迟绑定** 在某些情况下,`CALL` 指令的目标地址可能并非直接编码在指令中,而是通过寄存器或内存间接引用。例如: ```asm CALL DWORD PTR DS:[XXXXXXXX] ``` 这种情况下,OllyDbg 需要运行到该指令处才能解析出实际的目标地址。如果符号表中存在匹配项,则会直接显示符号名。这可能是导致未显示具体地址的原因之一。 #### 4. **插件或配置问题** OllyDbg 的行为也可能受到插件或用户配置的影响。例如,某些插件可能会自动解析符号并隐藏实际地址。可以通过禁用相关插件或调整设置来检查是否为插件引起的问题[^3]。 #### 示例代码片段 以下是一个典型的 `__security_init_cookie` 调用场景的反汇编代码示例: ```asm PUSH EBP MOV EBP, ESP CALL __security_init_cookie ``` ### 解决方法 若希望查看具体地址而非符号名,可以采取以下措施: - 确保 OllyDbg 的符号解析功能已关闭。 - 在运行时单步跟踪至 `CALL` 指令,观察寄存器或内存中的实际目标地址。 - 使用 `Ctrl+G` 手动跳转到符号对应的地址,验证其真实位置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值