C++逆アセンブリ-菱形継承

30434 ワード

「C++逆アセンブリと逆分析技術暴露」読書ノート.もうすぐ出張なので、帰ってから書きましょう.
一、概説
菱形継承は最も複雑なオブジェクト構造であり、菱形構造は単一の継承と多重の継承を組み合わせます.菱形継承の概略は次のとおりです.
class A;
class B : virtual public A;
class C : virtual public A;
class D : public B, public C;
 
ここで菱形継承には虚継承メカニズムが用いられる.虚継承は、継承定義にvirtualキーワードの継承関係が含まれていると定義されます.虚継承の提案は多重継承を解決するためである.ダミー継承を使用しない場合、DクラスオブジェクトはベースクラスAの2つのコピーを保存します.DクラスオブジェクトがベースクラスAメンバー変数またはメンバー関数を使用する場合、二義性が現れます.しかし、ダミー継承を採用すると、DクラスオブジェクトはベースクラスAのコピーを1部しか保持しませんが、コンパイラはどのようにしてこのメカニズムを実現しますか?
まず、単純な単一クラス継承から、派生クラスBの虚継承ベースクラスAのように説明する.
コンパイラは派生クラスBのオブジェクトにベースクラスAのコピーを保存し、クラスBのオブジェクトに変数を追加します.この変数はクラスAに関するデータのクラスBのオブジェクトにおけるオフセット量(offset)です.実際にクラスBのオブジェクトにはオフセット量(offset)の値を直接保存するのではなく、ポインタ(pvbtable)を保存します.このポインタはvbtableテーブル(virtual base table、ダミーベースクラステーブル)を指し、vbtableテーブルには2つの項目があります.
  • 第1項vbtable[1]:属するクラス(すなわち派生クラスB)に対応するダミーテーブルポインタのpvbtableに対するオフセット値;
  • 第2項vbtable[2]:ダミーベースクラス(すなわちベースクラスA)のダミーテーブルポインタのpvbtableに対するオフセット値.
  • すべてのクラスBのオブジェクトがテーブルを共有するため、各クラスBのオブジェクトは、テーブルを指す個別のポインタ(pvbtable)を有する.
    同様に,クラスCのオブジェクトにも同様にポインタ変数(pvbtable)があり,1つのvbtableテーブルを指す.
     
    1.派生クラスDのオブジェクトメモリ配列:
  • クラスBのダミーテーブルポインタ(pvftabe_B)
  • クラスBのダミーベースクラステーブルのポインタ(pvbtable_B)
  • クラスBのメンバーデータ
  • クラスCのダミーテーブルポインタ(pvftabe_C)
  • クラスCのダミーベースクラステーブルのポインタ(pvbtable_C)
  • クラスCのメンバデータ
  • クラスDのメンバデータ
  • クラスAのダミーテーブルポインタ(pvftabe_A)
  • クラスAのメンバデータ
  • クラスDのオブジェクトには、ベースクラスAデータのコピーが1部しか存在せず、以下の式があることは明らかである
      vbtable_B[2] + address[pvbtable_B] = vbtable_C[2] + address[pvbtable_C] = address[pvftabe_A].
    2.コンストラクタ
    オブジェクトDのコンストラクタ内では一度だけ祖父クラスAのコンストラクタが呼び出され、コンパイラはクラスB,C,Dのコンストラクタを呼び出すときに「コンストラクタタグ」というパラメータを追加します.例えば、B:B()コンストラクション関数を呼び出す場合、「コンストラクションタグ」=0の場合、親Aを用いたコンストラクション関数は呼び出されない.構築タグ=1の場合、親Aのコンストラクション関数が呼び出されます.D:D()コンストラクション関数を呼び出す場合、「コンストラクションタグ」=0の場合、祖父クラスAを用いたコンストラクション関数は呼び出されない.「コンストラクションタグ」=1の場合、祖父クラスAのコンストラクション関数が呼び出されます.
    具体的なプロセスは次のとおりです.
    ①「構築フラグ」を1に設定し、D:D()を呼び出す.
    ②D:D()内で、A:A()を呼び出す.
    ③D:D()内で「構築マーク」を0にしてB:B()を呼び出す.
    ④D:D()内で「構築マーク」を0にし、C:C()を呼び出す.
    3.構造関数
     
    オブジェクトDのコンストラクタ内では一度だけ祖父クラスAのコンストラクタが呼び出される.
    二、ソースコード(本の第十二章菱形継承ソースコード)
    //      ,    A  
    
    class CFurniture{  
    
    public:  
    
        CFurniture(){  
    
            m_nPrice = 0;  
    
        }  
    
        virtual ~CFurniture(){              //            
    
        printf("virtual ~CFurniture()\r
    "); } virtual int GetPrice(){ // return m_nPrice; }; protected: int m_nPrice; // }; // , CFurniture, B class CSofa : virtual public CFurniture{ public: CSofa(){ m_nPrice = 1; m_nColor = 2; } virtual ~CSofa(){ // printf("virtual ~CSofa()\r
    "); } virtual int GetColor(){ // return m_nColor; } virtual int SitDown(){ // return printf("Sit down and rest your legs\r
    "); } protected: int m_nColor; // }; // , CFurniture, C class CBed : virtual public CFurniture{ public: CBed(){ m_nPrice = 3; m_nLength = 4; m_nWidth = 5; } virtual ~CBed(){ // printf("virtual ~CBed()\r
    "); } virtual int GetArea(){ // return m_nLength * m_nWidth; } virtual int Sleep(){ // return printf("go to sleep\r
    "); } protected: int m_nLength; // int m_nWidth; }; // , CSofa CBed, D class CSofaBed : public CSofa, public CBed{ public: CSofaBed(){ m_nHeight = 6; } virtual ~CSofaBed(){ // printf("virtual ~CSofaBed()\r
    "); } virtual int SitDown(){ // return printf("Sit down on the sofa bed\r
    "); } virtual int Sleep(){ // return printf("go to sleep on the sofa bed\r
    "); } virtual int GetHeight(){ return m_nHeight; } protected: int m_nHeight; // }; void main(int argc, char* argv[]){ CSofaBed SofaBed; }

     
    三、アセンブリ(VS 2010コンパイル)
    1.メモリ配列
    ;                                                                                     
    
    ebp-28h    002BF950  00CD4854  pvftable1---->const CSofaBed::`vftable'{for `CSofa'}       
    
    ebp-24h    002BF954  00CD4870  pvbtable1---->const CSofaBed::`vbtable'{for `CSofa'}         
    
    ebp-20h    002BF958  00000002  CSofa.m_nColor                                      
    
    ebp-1Ch    002BF95C  00CD4844  pvftable2---->const CSofaBed::`vftable'{for `CBed'}     
    
    ebp-18h    002BF960  00CD4864  pvbtable2---->const CSofaBed::`vbtable'{for `CBed'}     
    
    ebp-14h    002BF964  00000004  CBed.m_nLength                                        
    
    ebp-10h    002BF968  00000005  CBed.m_nWidth                                       
    
    ebp-0Ch    002BF96C  00000006  CSofaBed.m_nHeight                             
    
    ebp-08h    002BF970  00CD4834  pvftable3---->const CSofaBed::`vftable'{for `CFurniture'}    
    
    ebp-04h    002BF974  00000003  CFurniture.m_nPrice                                         
    
                                                                                   
    
    
    
    ;     (pvftable1):
    
    ;const CSofaBed::`vftable'{for `CSofa'}                ;  CSofa   
    
    00CD4854  00CD10B4  CSofa::GetColor(void)
    
    00CD4858  00CD1005  CSofaBed::SitDown(void)
    
    00CD485C  00CD1127  CSofaBed::GetHeight(void)
    
    00CD4860  00000000
    
    
    
    ;      (vbtable1):
    
    ;const CSofaBed::`vbtable'{for `CSofa'}
    
    00CD4870  FFFFFFFC ;vbtable1[1]=-4, address[pvbtable1]+vbtable1[1]=address[pvftable1]
    
    00CD4874  0000001C ;vbtable1[2]=28, address[pvbtable1]+vbtable1[2]=address[pvftable3]
    
    00CD4878  00000000
    
    
    
    
    
    ;     (pvftable2):
    
    ;const CSofaBed::`vftable'{for `CBed'}                ;  CBed   
    
    00CD4844  00CD10FA  CBed::GetArea(void)
    
    00CD4848  00CD1091  CSofaBed::Sleep(void)
    
    00CD484C  00000000
    
    
    
    ;      (vbtable2):
    
    ;const CSofaBed::`vbtable'{for `CBed'}                
    
    00CD4864  FFFFFFFC ;vbtable2[1]=-4, address[pvbtable2]+vbtable2[1]=address[pvftable2]
    
    00CD4868  00000010 ;vbtable2[2]=16, address[pvbtable2]+vbtable2[2]=address[pvftable3]
    
    00CD486C  00000000
    
    
    
    
    
    ;     (pvftable3):
    
    ;const CSofaBed::`vftable'{for `CFurniture'}            ;   CFurniture   
    
    00CD4834  00CD1028  CSofaBed::`scalar deleting destructor'(uint)
    
    00CD4838  00CD1145  CFurniture::GetPrice(void)
    
    00CD483C  00000000

    2.コンストラクタ
    mov     [ebp-4], ecx               ;    this   [ebp-4]
    
    mov     dword ptr [ebp-48h], 0     ;     0
    
    cmp     dword ptr [ebp+8], 0    
    
    ;    [ebp+8]==0, 0              ; 1 ,            。
    
    jz      short loc_4114BC
    
    
    
    mov     eax, [ebp-4]                ;eax=this
    
    ;    [eax+4]=[this+4]=pvbtable1, pvbtable1    const CSofaBed::`vbtable'{for `CSofa'}
    
    mov     dword ptr [eax+4], offset ??_8CSofaBed@@7BCSofa@@@ 
    
    mov     eax, [ebp-4]                ;eax=this
    
    ;    [eax+10h]=[this+10h]=pvbtable2, pvbtable2    const CSofaBed::`vbtable'{for `CBed'}
    
    mov     dword ptr [eax+10h], offset ??_8CSofaBed@@7BCBed@@@ 
    
    mov     ecx, [ebp-4]                ;ecx=this
    
    add     ecx, 20h                    ;ecx+20h=this+20h----->pvftable3
    
    call    j_??0CFurniture@@QAE@XZ     ;         CFurniture::CFurniture(void)
    
    or      dword ptr [ebp-48h], 1      ;     1
    
    
    
    loc_4114BC:
    
    push    0                           ;    0,      ,     CFurniture     
    
    mov     ecx, [ebp-4]                ;ecx=this
    
    call    j_??0CSofa@@QAE@XZ          ;        CSofa::CSofa(void)
    
    push    0                           ;    0,      ,     CFurniture     
    
    mov     ecx, [ebp-4]                ;ecx=this
    
    add     ecx, 0Ch                    ;ecx=this+0ch----->pvftable2
    
    call    j_??0CBed@@QAE@XZ           ;        CBed::CBed(void)
    
    mov     eax, [ebp-4]                ;ecx=this
    
    ;[eax]=[this]----->pvftable1,    const CSofaBed::`vftable'{for `CSofa'}
    
    mov     dword ptr [eax], offset ??_7CSofaBed@@6BCSofa@@@ 
    
    mov     eax, [ebp-4]                ;ecx=this
    
    ;ecx=this+0ch----->pvftable2,     const CSofaBed::`vftable'{for `CBed'}
    
    mov     dword ptr [eax+0Ch], offset ??_7CSofaBed@@6BCBed@@@ 
    
    mov     eax, [ebp-4]                ;eax=this
    
    mov     ecx, [eax+4]                ;ecx=[this+4]=pvbtable1
    
    mov     edx, [ecx+4]                ;edx=[pvbtable1+4]=vbtable1[2]
    
    mov     eax, [ebp-4]                ;eax=this=address[pvftable1]
    
    ;[eax+edx+4]=[this+vbtable1[2]]----->pvftable3,    const CSofaBed::`vftable'{for `CFurniture'}
    
    mov     dword ptr [eax+edx+4], offset ??_7CSofaBed@@6BCFurniture@@@
    
    mov     eax, [ebp-4]                ;eax=this
    
    mov     dword ptr [eax+1Ch], 6      ;[eax+1ch]=[this+1ch]----->CSofaBed.m_nHeight,    6

     
    3.構造関数

    4.関数呼び出し
    CFurniture * pFurniture = &SofaBed; 
    
    mov     ecx, [ebp-24h]        ;      ,ecx=[ebp-24h]=[this+4]=pvbtable1,        
    
    mov     edx, [ecx+4]          ;edx=[pvbtable1+4]=vbtable2[2]
    
    lea     eax, [ebp+edx-24h]    
    ;pvbtable1+vbtable2[2]=address[pvftable3], eax=address[pvftable3]=this+20h。 mov [ebp-78h], eax mov ecx, [ebp-78h] mov [ebp-2Ch], ecx ; pFurniture [ebp-2Ch] , pFurniture=this+20h ;printf("price is %d", pFurniture->GetPrice()); mov eax, [ebp-2Ch] ; pFurniture eax, eax=this+20h mov edx, [eax] ;edx=[this+20h]=pvftable3 mov ecx, [ebp-2Ch] ;ecx ,ecx=this+20h----->pvftable3 mov eax, [edx+4]
    ;eax=[pvftable3+4]=vftable3[2]----->CFurniture::GetPrice(void) call eax ; CFurniture::GetPrice(void) push eax ;CFurniture::GetPrice(void) push offset Format ;"price is %d" call ds:__imp__printf add esp, 8 ;CSofa * pSofa = &SofaBed; lea eax, [ebp-28h] ; ,eax=address[ebp-28h]=this mov [ebp-30h], eax ; pSofa [ebp-30h] , pSofa , pSofa=this ;pSofa->SitDown(); mov eax, [ebp-30h] ;eax=pSofa=this mov edx, [eax] ;edx=[this]=pvftable1 mov ecx, [ebp-30h] ;ecx ,ecx=pSofa=this mov eax, [edx+4]
    ;eax=[pvftable1+4]=vftable1[2]----->CSofaBed::SitDown(void) call eax ; CSofaBed::SitDown(void) CBed * pBed = &SofaBed; lea ecx, [ebp-28h] ; ,ecx=address[ebp-28h]=this add ecx, 0Ch ;ecx=this+0ch----->pvftable2 mov [ebp-78h], ecx ; jmp short loc_41142E ;---| ;| loc_41142E:;<----------------| mov edx, [ebp-78h] mov [ebp-34h], edx
    ; pBed [ebp-34h] , pBed , pBed=this+0ch----->pvftable2 pBed->Sleep(); mov eax, [ebp-34h] ;eax=this+0ch mov edx, [eax] ;edx=[this+0ch]=pvftable2 mov ecx, [ebp-34h] ;ecx ,ecx=this+0ch----->pvftable2 mov eax, [edx+4]
    ;eax=[pvftable2+4]=vftable2[2]----->CSofaBed::Sleep(void) call eax ; CSofaBed::Sleep(void)