1. 程式人生 > >C++反匯編第一講,認識構造函數,析構函數,以及成員函數

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

在外 學習 詳解 局部變量 png 成員 log class dwt

          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指針)

   

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