C++反匯編第一講,認識構造函數,析構函數,以及成員函數


          C++反匯編第一講,認識構造函數,析構函數,以及成員函數

以前說過在C系列下的匯編,怎么認識函數.那么現在是C++了,隱含有構造和析構函數

 

 

一丶認識構造函數

高級代碼:

  

class MyTest
{
public:
    MyTest();
    ~MyTest();
public:
    DWORD m_dwTest;
};
 MyTest::MyTest()
 {
     printf("1111\r\n");        //構造的時候先打印
     
 }
 MyTest::~MyTest()
 {
    printf("2222\r\n");        //析構的時候打印
 }


int main(int argc, char* argv[])
{
    MyTest Test;              //創建局部對象
    getchar();
    return 0;
}

C++中的類,構造的時候先祖先類,然后父類,最后朋友類,然后在構造自己.  析構的時候 先自己 后朋友 接着父類 然后是祖先類,(明白一下順序)

Debug下的匯編代碼

  

這個是main函數內部,在創建對象的時候,會先調用構造,然后退出的時候會調用析構(上面是我改名字過后的)

現在我們認識構造有幾個必要條件

1.ecx,this傳參因為C++下的對象都是 thisCall,和FastCall類似,thisCall會通過寄存器傳參.而fastCall最后兩個參數會通過寄存器傳參.

.鑒定是ecx傳參的前提下是函數外面給值,函數內部使用

函數內部會將ecx給存儲起來,這個內存空間稱之為  this,也就是語法為什么可以這樣寫: this.xxxx = 1  this.MyTest();

高亮ecx傳參的時候的內存地址,會有多處使用. 

2.構造會在創建對象的時候先調用

3.構造函數的返回值則是this指針.

詳解怎么查看構造函數

1.是ecx傳參,確定了一個條件,其余兩個條件還沒有滿足

2.函數內部使用ecx,且給this指針賦值,並且返回了this指針

返回的匯編: 

3.該函數是當前棧作用域下的第一次調用

  

main函數中初始化成員變量為ccc之后,調用的第一個.

PS: 附加條件 我們點擊ecx傳參的時候的局部變量(this)會有多處使用.

一般來說確定上面三點則可以確定是構造函數了.上面三個都是必要條件.

而充分條件以后學習虛表的時候就知道了,構造會初始化虛表,且是第一個,所以可以直接確定是構造函數了.

 

說的聽過,其實看反匯編代碼也就3 - 4秒的事情.

Release下的匯編

根據上面代碼,可以確定

1.先調用的第一個函數

2.ecx傳參.並且內部使用了ecx,賦值給了this指針,且把this指針返回

 

 注意:構造函數,析構函數只能是thiscall,就算你自己加上調用約定,編譯的時候也提示是無效的調用約定,且反匯編代碼不會做任何改變.

總結:

  1.構造函數優先調用

  2.ecx傳參,且函數內部會將ecx給this賦值(this可能是一塊內存空間,也可能是寄存器變量)且返回this指針

  3.可以點擊this指針,可能會有多次調用

注: 構造析構都是thiscall,不能修改

 

 二丶識別析構函數

識別析構函數和構造函數類似

1.thiscall,並且最后調用

2.無返回值

看下析構函數

1.最后一次調用的

  

2.thiscall,無返回值,其內部會使用ecx給this賦值

 

  

 Release下的匯編和Debug下一樣,有優化,可能你不使用this則不會給this賦值.但是還是無返回值

 總結:

  1.析構最后一次調用

  2.thiscall傳參

  3.無返回值

三丶識別成員函數(c call  thiscall  fastcall  stdcall)

高級代碼:

  

class MyTest
{
public:
    MyTest();
    ~MyTest();
    void SetTest(DWORD dwTest);
    DWORD GetTest();
public:
    DWORD m_dwTest;
};
 MyTest::MyTest()
 {
     printf("1111\r\n");
     
 }
 MyTest::~MyTest()
 {
    printf("2222\r\n");
 }


void MyTest::SetTest(DWORD dwTest)
{
    this->m_dwTest = dwTest;   
}
DWORD MyTest::GetTest()
{
    return this->m_dwTest;
}
int main(int argc, char* argv[])
{
    MyTest Test;
    Test.SetTest(1);      
    int Number = Test.GetTest();      //添加了Set,Get方法,並調用
    getchar();
    return 0;
}

看上面,我們可以看出都是默認的thiscall,看下反匯編代碼 (看各種調用約定會產生什么樣的結果)

1.默認的thiscall在匯編中的表現形式

Debug下的反匯編

頭尾是構造和析構,中間則是我們的SetGet方法,可以看出,如果是thiscall,那么是ecx傳參,且里面ecx會給this指針賦值,且返回this指針

Release和Debug類似,可能有少許優化,為了篇幅原因,不在截圖. 

2.Stdcall 成員函數表現形式

看上面匯編代碼得出

1.this指針是  ebp + var_10,

2.在stdcall下,會將this指針給寄存器,然后push進去

總結:

  1.stdcall 會將this指針當做參數push進去.

  2. push進去的this指針,會在call上面第一個push,也就是說this指針是第一個參數

  3.平棧還是按照stdcall的形式平棧

 

 3.C call下的匯編表現形式

  

也是通過push的方式,將this指針當做參數傳遞

然后c調用約定在外面平棧

4.fastCall的匯編表現形式

 寄存器傳參,然后ecx是外部更改,內部使用

 

最終的大總結:

    1).識別構造

      1.構造函數優先調用

      2.ecx傳參,且函數內部會將ecx給this賦值(this可能是一塊內存空間,也可能是寄存器變量)且返回this指針

      3.可以點擊this指針,可能會有多次調用

      注: 構造析構都是thiscall,不能修改

 

    2).識別析構

      1.析構最后一次調用

      2.thiscall傳參

      3.無返回值

  

    3).識別各種調用約定的成員函數

       1.c調用約定,會將this指針push進去,然后平棧按照c調用約定平棧

       2.stdcall,會將this指針push進去,內部平棧

      3.thiscall會默認使用ecx,外部更改,內部使用,平棧和stdcall一樣

      4.fastcall,會使用兩個寄存器傳參,且也會外部更改ecx,內部使用.

      5.c約定,std約定,push的時候都是this指針,且是第一個參數(也就是call上面的最近的一個push,必定為this指針)

 

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM