0xCC

在VC++编写的程序编程成Debug版,反汇编代码,函数入口处经常看到如下一段代码:

00EA14E0 55                   push    ebp  
00EA14E1 8B EC                mov     ebp,esp
00EA14E3 81 EC C0 00 00 00    sub     esp,0C0h
00EA14E9 53                   push    ebx  
00EA14EA 56                   push    esi  
00EA14EB 57                   push    edi  
00EA14EC 8D BD 40 FF FF FF    lea     edi,[ebp-0C0h]
00EA14F2 B9 30 00 00 00       mov     ecx,30h
00EA14F7 B8 CC CC CC CC       mov     eax,0CCCCCCCCh
00EA14FC F3 AB                rep stos  dword ptr es:[edi]

其中主要分为3部分,最上面3行完成本函数局部变量栈空间的开辟,中间部分保存需要保护的寄存器(这部分并非必须),最后4行完成栈空间所有字节初始化为0xCC。
0xCC对应汇编代码 int 3,即软断点。

一方面,0xCC可以为某些检查提供标记(_RTC_CheckStackVars);另一方面,在栈操作错误或调试汇编代码(如使用OD调试shellcode)时可以对感兴趣的逻辑进行细致的分析,这通常可以通过加入

__asm {
  int 3;   // 或 _emit 0xcc
};

来加入断点。

_RTC_CheckEsp

注意,这个是在Debug下build时才有的,用于快速定位debug版程序栈操作错误。跟/GS是没有关系的。

esp_check: 堆栈平衡检查,在调用printf前保存esp到esi,在调用printf后,比较esi与esp达到检查esp的目的。

010A14FE 8B F4             mov     esi,esp                       
010A1500 68 78 57 0A 01    push    offset string "call printf.\n" (10A5778h)  
010A1505 FF 15 BC 82 0A 01 call    dword ptr [__imp__printf (10A82BCh)]       
010A150B 83 C4 04          add     esp,4                      
010A150E 3B F4             cmp     esi,esp                      
010A1510 E8 35 FC FF FF    call    @ILT+325(__RTC_CheckEsp) (10A114Ah)   

_RTC_CheckEsp:
010A15D0 75 01           jne     esperror (10A15D3h)
010A15D2 C3              ret  

esperror:
010A15D3 55              push    ebp  
010A15D4 8B EC           mov     ebp,esp
010A15D6 83 EC 00        sub     esp,0
010A15D9 50              push    eax  
010A15DA 52              push    edx  
010A15DB 53              push    ebx  
010A15DC 56              push    esi  
010A15DD 57              push    edi  
010A15DE 8B 45 04        mov     eax,dword ptr [ebp+4]
010A15E1 6A 00           push    0  
010A15E3 50              push    eax  
010A15E4 E8 C5 FB FF FF  call    _RTC_Failure (10A11AEh)
010A15E9 83 C4 08        add     esp,8
010A15EC 5F              pop     edi  
010A15ED 5E              pop     esi  
010A15EE 5B              pop     ebx  
010A15EF 5A              pop     edx  
010A15F0 58              pop     eax  
010A15F1 8B E5           mov     esp,ebp
010A15F3 5D              pop     ebp  
010A15F4 C3              ret  

这里没有继续深入_RTC_Failure,这个是进行错误提示终止程序的,或许与下面的_RTC_CheckStackVars提示类似。

_RTC_CheckStackVars

_RTC_CheckStackVars 是新版VS(没有深究从哪个版本开始,但vs2008是有这个特性的)为Debug下build的程序提供栈操作错误的检查,方便在快速发现错误。下面是相关的处理流程,这个和/GS保护机制不是一回事。

struct SVarsInfo
{
  DWORD dwVarNum;   //需要验证的参数个数
  struct SVarBlock
  {
    DWORD dwOffset;   //相对当前ESP的偏移,由于栈向下增长,所以这里是个 负数
    DWORD dwSize;   //当前参数占用的字节总数
    PCHAR strVarName; //当前变量的名称
  }* pVarBlockArr;  //这个是指向存储变量详细信息数据的数组的指针
}

_RTC_CheckStackVars(PVOID pVarInfo, _RTC_framedesc* pEBP)
{
  DWORD dwEBP = pEBP;
  SVarsInfo* varsInfo = (SVarInfo*)pVarInfo;
  for(int i=0; idwVarNum; i++)
  {
    SVarBlock* varN = varsInfo->pVarBlockArr;
    if(*(PDWORD)(dwEBP+varN->dwOffset-4)!=0xCCCCCCCC)
      _RTC_StackFailure(参数首部, 参数尾部); 
    if(*(PDWORD)(dwEBP+varN->dwOffset+varN->dwSize)!=0xCCCCCCCC)
      _RTC_StackFailure(参数首部, 参数尾部);
  }
}

上面是基本的_RTC_CheckStackVars的伪代码逻辑。

报错内容如下:

---------------------------
Microsoft Visual C++ Debug Library
---------------------------
Debug Error!

Program: e:\path\to\my.exe
Module: e:\path\to\my.exe
File: e:\path\to\my.cpp
Line: 19

Run-Time Check Failure #2 - Stack around the variable 'strTemp' was corrupted.

(Press Retry to debug the application)
---------------------------
中止(A) 重试(R) 忽略(I)
---------------------------