上文说明了C++反汇编后的EBP,ESP寄存器都是做什么用的,相信大家已经有所了解,如果有没看过的请参考下文:
http://www.cnblogs.com/pugang/archive/2012/05/25/2518499.html
本文不会对其再做过多的讲解,如果还有问题,欢迎大家留言讨论。
首先明确本文要解决的问题:在没有源代码的情况下如何看明白我们的汇编代码中哪些是局部变量。
为了便于说明我将C++代码和汇编代码在一起,完整代码如下:
int InternalFunctionA(int nSizeA1, int nSizeA2)
{
00401000 push ebp
00401001 mov ebp,esp
00401003 sub esp,0Ch
int localnSizeA1 = nSizeA1;
00401006 mov eax,dword ptr [nSizeA1]
00401009 mov dword ptr [localnSizeA1],eax
int localnSizeA2 = nSizeA2;
0040100C mov ecx,dword ptr [nSizeA2]
0040100F mov dword ptr [localnSizeA2],ecx
int nFunctionA = localnSizeA1 + localnSizeA2;
00401012 mov edx,dword ptr [localnSizeA1]
00401015 add edx,dword ptr [localnSizeA2]
00401018 mov dword ptr [nFunctionA],edx
return nFunctionA;
0040101B mov eax,dword ptr [nFunctionA]
}
0040101E mov esp,ebp
00401020 pop ebp
00401021 ret
int InternalFunctionB(int nSizeB1, int nSizeB2)
{
00401030 push ebp
00401031 mov ebp,esp
00401033 push ecx
int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
00401034 mov eax,dword ptr [nSizeB2]
00401037 push eax
00401038 mov ecx,dword ptr [nSizeB1]
0040103B push ecx
0040103C call InternalFunctionA (401000h)
00401041 add esp,8
00401044 mov dword ptr [nFunctionA],eax
return 0;
00401047 xor eax,eax
}
00401049 mov esp,ebp
0040104B pop ebp
0040104C ret
int _tmain(int argc, _TCHAR* argv[])
{
00401050 push ebp
00401051 mov ebp,esp
00401053 push ecx
int nFunctionVal = InternalFunctionB(36, 64);
00401054 push 40h
00401056 push 24h
00401058 call InternalFunctionB (401030h)
0040105D add esp,8
00401060 mov dword ptr [nFunctionVal],eax
cout<<"Hello SolidMango!"<<endl;
00401063 mov eax,dword ptr [__imp_std::endl (402048h)]
00401068 push eax
00401069 push offset ___xi_z+3Ch (402154h)
0040106E mov ecx,dword ptr [__imp_std::cout (402078h)]
00401074 push ecx
00401075 call std::operator<<<std::char_traits<char> > (401280h)
0040107A add esp,8
0040107D mov ecx,eax
0040107F call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40205Ch)]
return 0;
00401085 xor eax,eax
}
00401087 mov esp,ebp
00401089 pop ebp
0040108A ret
{
00401000 push ebp
00401001 mov ebp,esp
00401003 sub esp,0Ch
int localnSizeA1 = nSizeA1;
00401006 mov eax,dword ptr [nSizeA1]
00401009 mov dword ptr [localnSizeA1],eax
int localnSizeA2 = nSizeA2;
0040100C mov ecx,dword ptr [nSizeA2]
0040100F mov dword ptr [localnSizeA2],ecx
int nFunctionA = localnSizeA1 + localnSizeA2;
00401012 mov edx,dword ptr [localnSizeA1]
00401015 add edx,dword ptr [localnSizeA2]
00401018 mov dword ptr [nFunctionA],edx
return nFunctionA;
0040101B mov eax,dword ptr [nFunctionA]
}
0040101E mov esp,ebp
00401020 pop ebp
00401021 ret
int InternalFunctionB(int nSizeB1, int nSizeB2)
{
00401030 push ebp
00401031 mov ebp,esp
00401033 push ecx
int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
00401034 mov eax,dword ptr [nSizeB2]
00401037 push eax
00401038 mov ecx,dword ptr [nSizeB1]
0040103B push ecx
0040103C call InternalFunctionA (401000h)
00401041 add esp,8
00401044 mov dword ptr [nFunctionA],eax
return 0;
00401047 xor eax,eax
}
00401049 mov esp,ebp
0040104B pop ebp
0040104C ret
int _tmain(int argc, _TCHAR* argv[])
{
00401050 push ebp
00401051 mov ebp,esp
00401053 push ecx
int nFunctionVal = InternalFunctionB(36, 64);
00401054 push 40h
00401056 push 24h
00401058 call InternalFunctionB (401030h)
0040105D add esp,8
00401060 mov dword ptr [nFunctionVal],eax
cout<<"Hello SolidMango!"<<endl;
00401063 mov eax,dword ptr [__imp_std::endl (402048h)]
00401068 push eax
00401069 push offset ___xi_z+3Ch (402154h)
0040106E mov ecx,dword ptr [__imp_std::cout (402078h)]
00401074 push ecx
00401075 call std::operator<<<std::char_traits<char> > (401280h)
0040107A add esp,8
0040107D mov ecx,eax
0040107F call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (40205Ch)]
return 0;
00401085 xor eax,eax
}
00401087 mov esp,ebp
00401089 pop ebp
0040108A ret
调用过程如下图所示,下面请大家和我一起看代码,InternalFunctionA()中,一共3个整型的变量,localnSizeA1 ,localnSizeA2,nFunctionA ,
00401003 sub esp,0Ch
这条指令的意思是说在栈上面给这3个局部变量留空间,执行完这条指令,栈顶已经移到ebp- 0ch的位置了,说到这里相信大家已经明白了,从ebp开始,局部变量一定在比这个地址低的位置,也就是ebp-nValue,也就是找到了局部变量。
总结:
也许有人会问我写这几篇关于C++反汇编文章的意义在那里,我先简单说明一下:
1. 有些情况下调试的时候由于C++还是相对高级的语言,在做某些问题分析比如dump file 分析的时候,C++的粒度还是显的有些大,看不到位。
2. 有时候我们根本就没有C++代码,我们只有一些dll和exe, 系统跑出问题同样需要分析解决。
3. 反病毒方面相信不必多言。