標籤:this指標 改變 局部變數 getch get 根據 font cal 圖片
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++反組譯碼第一講,認識建構函式,解構函式,以及成員函數