VC++中反汇编0xCC,_RTC_CheckEsp与_RTC_CheckStackVars
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)
---------------------------