zoukankan      html  css  js  c++  java
  • 逆向分析一个完整的C++程序包含寄存器与参数传递详解

    最近在分析C++ dump 文件的时候觉得有必要将一些必要的反汇编东西总结一下以备别人参考,自己有时间的时候也可以进行更多的改进。下面通过一个简单的C++代码转成汇编代码后的详细解释说明一下C++和汇编的对应关系,以及如何识别汇编代码中进行的一些操作的意义。代码的调用关系如下图所示:

    完整C++代码下:

     

     

    int InternalFunctionA(int nSizeA1, int nSizeA2)
    {
        int localnSizeA1 = nSizeA1;
        int localnSizeA2 = nSizeA2;

        int nFunctionA = localnSizeA1 + localnSizeA2;

        return nFunctionA;
    }

    int InternalFunctionB(int nSizeB1, int nSizeB2)
    {

        int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
        return 0;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        
        int nFunctionVal = InternalFunctionB(3664);
        cout<<"Hello SolidMango!"<<endl;
        return 0;

    }

     

    那么这段简单的C++代码在转换成汇编代码之后是什么样子的呢?让我们拭目以待,首先让我们看看main函数转换后的代码(debug版), 如下,我们逐条来进行分析,

     

    int _tmain(int argc, _TCHAR* argv[])
    {
    00411570  push        ebp  //栈底压栈
    00411571  mov         ebp,esp //栈底下移,更详细的请参考我关于ebp,esp的解释
    00411573  sub         esp,0CCh //局部变量预留空间
    00411579  push        ebx  //保存ebx  
    0041157A  push        esi  //保存esi  
    0041157B  push        edi  //保存edi  
    0041157C  lea         edi,[ebp-0CCh] //下移edi到栈顶
    00411582  mov         ecx,33h //0CCh/4 = 33h
    00411587  mov         eax,0CCCCCCCCh //eax赋值
    0041158C  rep stos    dword ptr es:[edi] //从edi开始做33h次赋值0CCCCCCCCh ,初始化栈内存
        
        int nFunctionVal = InternalFunctionB(3664);
    0041158E  push        40h  //参数64入栈,
    00411590  push        24h  //参数36入栈
    00411592  call        InternalFunctionB (41101Eh) );//到41101Eh处函数调用
    00411597  add         esp,8 //函数调用后将参数弹出,清理栈
    0041159A  mov         dword ptr [nFunctionVal],eax 
        cout<<"Hello SolidMango!"<<endl;
    0041159D  mov         esi,esp 
    0041159F  mov         eax,dword ptr [__imp_std::endl (41A338h)] 
    004115A4  push        eax  
    004115A5  push        offset string "Hello SolidMango!" (417800h) 
    004115AA  mov         ecx,dword ptr [__imp_std::cout (41A33Ch)] 
    004115B0  push        ecx  
    004115B1  call        std::operator<<<std::char_traits<char> > (411163h) 
    004115B6  add         esp,8 
    004115B9  mov         ecx,eax 
    004115BB  call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (41A320h)] 
    004115C1  cmp         esi,esp 
    004115C3  call        @ILT+430(__RTC_CheckEsp) (4111B3h) 
        return 0;
    004115C8  xor         eax,eax 

    }
    004115CA  pop         edi  //恢复edi
    004115CB  pop         esi  //恢复esi
    004115CC  pop         ebx  //恢复ebx
    004115CD  add         esp,0CCh //栈顶上移
    004115D3  cmp         ebp,esp //检查栈平衡
    004115D5  call        @ILT+430(__RTC_CheckEsp) (4111B3h) 
    004115DA  mov         esp,ebp //恢复上一个栈帧的ebp,esp
    004115DC  pop         ebp  
    004115DD  ret//函数返回

     

     另外两层函数调用的汇编代码如下,感兴趣的读者可以对比一下,和main函数的过程相似,

     

    int InternalFunctionA(int nSizeA1, int nSizeA2)
    {
    004114C0  push        ebp  
    004114C1  mov         ebp,esp 
    004114C3  sub         esp,0E4h 
    004114C9  push        ebx  
    004114CA  push        esi  
    004114CB  push        edi  
    004114CC  lea         edi,[ebp-0E4h] 
    004114D2  mov         ecx,39h 
    004114D7  mov         eax,0CCCCCCCCh 
    004114DC  rep stos    dword ptr es:[edi] 
        int localnSizeA1 = nSizeA1;
    004114DE  mov         eax,dword ptr [nSizeA1] 
    004114E1  mov         dword ptr [localnSizeA1],eax 
        int localnSizeA2 = nSizeA2;
    004114E4  mov         eax,dword ptr [nSizeA2] 
    004114E7  mov         dword ptr [localnSizeA2],eax 

        int nFunctionA = localnSizeA1 + localnSizeA2;
    004114EA  mov         eax,dword ptr [localnSizeA1] 
    004114ED  add         eax,dword ptr [localnSizeA2] 
    004114F0  mov         dword ptr [nFunctionA],eax 

        return nFunctionA;
    004114F3  mov         eax,dword ptr [nFunctionA] 
    }
    004114F6  pop         edi  
    004114F7  pop         esi  
    004114F8  pop         ebx  
    004114F9  mov         esp,ebp 
    004114FB  pop         ebp  
    004114FC  ret   
    int InternalFunctionB(int nSizeB1, int nSizeB2)
    {
    00411510  push        ebp  
    00411511  mov         ebp,esp 
    00411513  sub         esp,0CCh 
    00411519  push        ebx  
    0041151A  push        esi  
    0041151B  push        edi  
    0041151C  lea         edi,[ebp-0CCh] 
    00411522  mov         ecx,33h 
    00411527  mov         eax,0CCCCCCCCh 
    0041152C  rep stos    dword ptr es:[edi] 

        int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
    0041152E  mov         eax,dword ptr [nSizeB2] 
    00411531  push        eax  
    00411532  mov         ecx,dword ptr [nSizeB1] 
    00411535  push        ecx  
    00411536  call        InternalFunctionA (411140h) 
    0041153B  add         esp,8 
    0041153E  mov         dword ptr [nFunctionA],eax 
        return 0;
    00411541  xor         eax,eax 
    }
    00411543  pop         edi  
    00411544  pop         esi  
    00411545  pop         ebx  
    00411546  add         esp,0CCh 
    0041154C  cmp         ebp,esp 
    0041154E  call        @ILT+430(__RTC_CheckEsp) (4111B3h) 
    00411553  mov         esp,ebp 
    00411555  pop         ebp  
    00411556  ret

     

    总结:通过这几篇文章的总结,相信大家已经可以看懂一些常规的C++反汇编代码,应该可以对付一般的应用,如果大家还有什么问题,或者建议欢迎讨论。

  • 相关阅读:
    Python中的memoryview
    Python常见陷阱
    特殊方法 之 len __repr__ __str__
    collections模块
    使用math中的hypot实现向量
    Ellipsis对象
    array
    标准库heapq的使用
    Mysql常用命令
    使用npm查看安装的包
  • 原文地址:https://www.cnblogs.com/pugang/p/2541683.html
Copyright © 2011-2022 走看看