今有c++程式:
class CA
{
public:
CA(int n1=0):_n1(n1){}
virtual void vf1(){}
private:
int _n1;
};
class CAsub:CA
{
public:
CAsub(int n1=0,int n2=1):CA(n1),_n2(n2){}
virtual void vf1(){}
virtual void vf2(){}
private:
int _n2;
};
int main(int argc, char* argv[])
{
CAsub casub;//此處設斷點跟入, goto 分析1:
casub->vf1();//此處設斷點跟入, goto 分析2:
CAsub *pcasub=new CAsub;
pcasub->vf1();//此處設斷點跟入, goto 分析3
pcasub->vf2();//此處設斷點跟入, goto 分析3
return 0;
}
vc6.0反組譯碼如下(各種編譯器細節可能不一樣,但方法應該都是類似的):
==================================================分析1:(建構函式分析)
...//main函數
00401068 push 1 ;從右至左壓入參數,傳說中的__stdcall方式?
0040106A push 0
0040106C lea ecx,[ebp-0Ch] ;傳說中的this指標
0040106F call @ILT+10(CAsub::CAsub) (0040100f) ;調用建構函式
...
...//CAsub的建構函式
004010A0 push ebp
004010A1 mov ebp,esp
004010A3 sub esp,44h
004010A6 push ebx
004010A7 push esi
004010A8 push edi
004010A9 push ecx
004010AA lea edi,[ebp-44h]
004010AD mov ecx,11h
004010B2 mov eax,0CCCCCCCCh
004010B7 rep stos dword ptr [edi]
//以上部分的分析見前一篇文章
004010B9 pop ecx
004010BA mov dword ptr [ebp-4],ecx ;this指標被存放到棧內臨時區的第一個位置
004010BD mov eax,dword ptr [ebp+8] ;取參數n1,注意在ebp與n1間還有一個四位元組返回地址
004010C0 push eax
004010C1 mov ecx,dword ptr [ebp-4]
004010C4 call @ILT+25(CA::CA) (0040101e) ;n1再次壓入堆棧,調用基類CA的建構函式(this指標相同)
004010C9 mov ecx,dword ptr [ebp-4]
004010CC mov edx,dword ptr [ebp+0Ch] ;取參數n2
004010CF mov dword ptr [ecx+8],edx ;初始化casub的n2參數(因為虛函數表指標佔用了開頭的4位元組,所以是this+8)
004010D2 mov eax,dword ptr [ebp-4]
004010D5 mov dword ptr [eax],offset CAsub::`vftable' (0041f01c) ;初始話虛函數表指標
//以下部分沒有分析價值
004010DB mov eax,dword ptr [ebp-4]
004010DE pop edi
004010DF pop esi
004010E0 pop ebx
004010E1 add esp,44h
004010E4 cmp ebp,esp
004010E6 call __chkesp (004011f0)
004010EB mov esp,ebp
004010ED pop ebp
004010EE ret 8
...
==================================================分析2:(類對象如何調用虛擬函數)
; casub.vf1();
00401089 lea ecx,[ebp-18h]
0040108C call @ILT+15(CAsub::vf1) (00401014)
//由上面的彙編代碼看出,並沒有什麼動態綁定,編譯器直接調用了類CAsub的vf1函數地址
==================================================分析3:(類指標對象如何調用虛擬函數)
; pcasub->vf1();
004010D6 mov edx,dword ptr [ebp-1Ch] ;pacsub入edx
004010D9 mov eax,dword ptr [edx] ;pacsub的虛函數表指標入eaxp[也即虛擬表的入口地址]
004010DB mov esi,esp ;
004010DD mov ecx,dword ptr [ebp-1Ch] ;this指標(pacsub)
004010E0 call dword ptr [eax] ;此處解釋為[eax+0],因為vf1在表中的第1項
...
; pcasub->vf2();
004010D6 mov edx,dword ptr [ebp-1Ch]
004010D9 mov eax,dword ptr [edx]
004010DB mov esi,esp
004010DD mov ecx,dword ptr [ebp-1Ch]
004010E0 call dword ptr [eax+4] ;vf2在表中的第2項