1、C++類代碼的特點
寄存器ECX傳參時一般用作this指針(對象地址)或是計數器。
有ecx傳參的call,是成員函數,構造函數,析構函數
能訪問成員變量的函數都會有ecx傳參
靜態函數、全局函數無ecx(this指針)
返回值
寄存器eax一般用作返回值
識別構造函數的OD反匯編代碼
特點:
(1) 代碼特點:沒有返回值、用於初始化
(2)反匯編特點:有返回值,而且是this指針
根據反匯編可以看出成員變量的順序,因為在內存數據中的排布順序是由代碼中成員變量定義順序決定的。
識別構造函數的辦法:
(1)構造函數調用時,會使用ECX用於this指針
(2)構造函數在反匯編層有返回值,是eax存放this指針
(3)構造函數用於初始化,一般內存如果是未初始化的比如CCCCCCC,經過構造函數會完成初始化。
(4)如果一個函數有對前4字節初始化為一個指針地址,那么可能是在初始化虛函數表指針。
如果一個類有虛函數,那么對象的內存數據里會有虛函數指針的定義。構造函數會初始化虛函數表指針,而類中定義多少個虛函數也只有一個虛函數表指針。
識別成員函數的OD反匯編代碼
特點:
(1)ECX傳遞this指針,調用成員函數
(2)成員函數中會訪問exc所指向的內存空間
成員函數與虛函數本身沒有什么區別,所以反匯編出來的代碼都差不多。
識別成員函數:
(1)如果找到了構造函數,那么下面調用的應該都是成員函數
(2)成員函數有this指針
(3)成員函數會訪問成員變量,即this指針指向的內存空間
識別析構函數的OD反匯編代碼
特點與識別:
(1)有ECX
(2)用於釋放資源,可能有delete,free等
(3)一般是在函數返回時,編譯器生成的調用。
全局構造與析構函數
初始化全局對象的構造函數,是在main函數之前,C運行庫初始化的代碼中_initterm函數
操作:
在return下斷點,main函數執行完畢后F11繼續執行,繼續F11return會返回到上一個調用函數。
exit(xxx) 調用析構函數
有虛函數的派生類
派生類對象的構造初始化
大致流程:
派生類的構造函數
{
基類的構造函數(函數中會初始化虛函數表指針)
初始化虛函數表指針
初始化數據
}
虛函數表創建
虛函數表是在程序編譯時就生成了,而且存儲在程序的只讀區段中
程序中如果創建了多個對象,只會有一個虛函數表,共用一個虛函數表。
C++中的多態實現
//多態的實現
A* pObj = &obj;
pObj->printfD();
模擬反匯編的調用流程
A* pObj = &obj;
測試代碼
#include "stdafx.h"
class A
{
public:
A::A() {
c = 3;
m = 1;
n = 2;
};
virtual void printA() { printf(" A::A\n "); };
virtual void printB() { printf(" A::B\n "); };
virtual void printC() { printf(" A::C\n "); };
void printfD() {
printf("(%d,%d)\n",m,n);
printf("hahahahaah");
};
A::~A() {
printf(" A::~A\n ");
};
protected:
private:
int n;
int c;
int m;
};
int main()
{
A obj;
obj.printA();
obj.printfD();
printf(" %d\n ",sizeof(obj));
printf(" 3333333333333333333333333\n ");
return 0;
}