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指針)
C++反匯編第一講,認識構造函數,析構函數,以及成員函數