《黑客反汇编揭密》第8章:虚函数分析

《黑客反汇编揭密》第8章第2小节的虚函数的示例38,其所分析的结果是在使用优化选项后编译所得。
所以,在书上,我们没有看到C++语义所说的,在new之后对类的构造函数的调用:如果有默认的则调用默认的,如果有自定义的,则自动调用用户自定义的构造函数。

所以在我采用默认的选项重新编译了一个。
下面贴出我得到的结果(平台VS2008,默认选项,命令行下编译:
示例代码:


#include

class Base{
  public:
    virtual void demo(){
      printf("BASE\n");
    }
    virtual void demo_2(){
      printf("BASE DEMO 2\n");
    }
    void demo_3(){
      printf("Nonvirtual BASE DEMO 3\n");
    }
};

class Derived:public Base{
  public:
    virtual void demo(){
      printf("DERIVED\n");
    }
    virtual void demo_2(){
      printf("DERIVED DEMO 2\n");
    }
    void demo_3(){
      printf("Nonvirtual DERIVED DEMO 3\n");
    }
};

int main(){
  Base *p=new Base;
  p->demo();
  p->demo_2();
  p->demo_3();
  
  p=new Derived;
  p->demo();
  p->demo_2();
  p->demo_3();
}

用IDA 5.2反汇编得到的结果:


.text:00401000 sub_401000      proc near               ; CODE XREF: start-5Cp
.text:00401000
.text:00401000 var_14          = dword ptr -14h
.text:00401000 var_10          = dword ptr -10h
.text:00401000 var_C           = dword ptr -0Ch
.text:00401000 var_8           = dword ptr -8
.text:00401000 var_4           = dword ptr -4
.text:00401000
.text:00401000                 push    ebp
.text:00401001                 mov     ebp, esp
.text:00401003                 sub     esp, 14h
.text:00401006                 push    4
.text:00401008                 call    new             ; 调用new操作分配内存
.text:0040100D                 add     esp, 4
.text:00401010                 mov     [ebp+var_8], eax ; 保存分配到的指针到ebp+var_8
.text:00401013                 cmp     [ebp+var_8], 0
.text:00401017                 jz      short loc_401026
.text:00401019                 mov     ecx, [ebp+var_8] ; 利用ECX来传递this指针
.text:0040101C                 call    Base__Constructor ; 调用Base的默认构造函数
.text:00401021                 mov     [ebp+var_10], eax ; 保存初始化后的实例指针到ebp+var_10
.text:00401024                 jmp     short loc_40102D
.text:00401026 ; ---------------------------------------------------------------------------
.text:00401026
.text:00401026 loc_401026:                             ; CODE XREF: sub_401000+17j
.text:00401026                 mov     [ebp+var_10], 0
.text:0040102D
.text:0040102D loc_40102D:                             ; CODE XREF: sub_401000+24j
.text:0040102D                 mov     eax, [ebp+var_10]
.text:00401030                 mov     [ebp+var_4], eax
.text:00401033                 mov     ecx, [ebp+var_4]
.text:00401036                 mov     edx, [ecx]
.text:00401038                 mov     ecx, [ebp+var_4] ; this指针
.text:0040103B                 mov     eax, [edx]      ; 获得实例的第一个虚函数地址到EAX
.text:0040103D                 call    eax             ; virtual void Base::demo()
.text:0040103F                 mov     ecx, [ebp+var_4]
.text:00401042                 mov     edx, [ecx]
.text:00401044                 mov     ecx, [ebp+var_4]
.text:00401047                 mov     eax, [edx+4]    ; 移动Vtbl指针,保存地址到EAX
.text:0040104A                 call    eax             ; virtual void Base::demo_2()
.text:0040104C                 mov     ecx, [ebp+var_4]
.text:0040104F                 call    sub_4010B0      ; void Base::demo_3()
.text:0040104F                                         ; 对于非虚函数,直接调用
.text:00401054                 push    4
.text:00401056                 call    new
.text:0040105B                 add     esp, 4
.text:0040105E                 mov     [ebp+var_C], eax
.text:00401061                 cmp     [ebp+var_C], 0
.text:00401065                 jz      short loc_401074
.text:00401067                 mov     ecx, [ebp+var_C]
.text:0040106A                 call    Derived__Constructor ; 调用Derived的默认构造函数
.text:0040106F                 mov     [ebp+var_14], eax ; 保存初始化后的实例指针到ebp+var_14
.text:00401072                 jmp     short loc_40107B
.text:00401074 ; ---------------------------------------------------------------------------
.text:00401074
.text:00401074 loc_401074:                             ; CODE XREF: sub_401000+65j
.text:00401074                 mov     [ebp+var_14], 0
.text:0040107B
.text:0040107B loc_40107B:                             ; CODE XREF: sub_401000+72j
.text:0040107B                 mov     ecx, [ebp+var_14]
.text:0040107E                 mov     [ebp+var_4], ecx
.text:00401081                 mov     edx, [ebp+var_4]
.text:00401084                 mov     eax, [edx]
.text:00401086                 mov     ecx, [ebp+var_4]
.text:00401089                 mov     edx, [eax]
.text:0040108B                 call    edx
.text:0040108D                 mov     eax, [ebp+var_4]
.text:00401090                 mov     edx, [eax]
.text:00401092                 mov     ecx, [ebp+var_4]
.text:00401095                 mov     eax, [edx+4]
.text:00401098                 call    eax
.text:0040109A                 mov     ecx, [ebp+var_4]
.text:0040109D                 call    sub_4010B0
.text:004010A2                 xor     eax, eax
.text:004010A4                 mov     esp, ebp
.text:004010A6                 pop     ebp
.text:004010A7                 retn
.text:004010A7 sub_401000      end

类Base的默认构造函数:


.text:004010D0 Base__Constructor proc near             ; CODE XREF: sub_401000+1Cp
.text:004010D0                                         ; Derived__Constructor+Ap
.text:004010D0
.text:004010D0 var_4           = dword ptr -4
.text:004010D0
.text:004010D0                 push    ebp
.text:004010D1                 mov     ebp, esp
.text:004010D3                 push    ecx
.text:004010D4                 mov     [ebp+var_4], ecx
.text:004010D7                 mov     eax, [ebp+var_4]
.text:004010DA                 mov     dword ptr [eax], offset off_40A16C
.text:004010E0                 mov     eax, [ebp+var_4]
.text:004010E3                 mov     esp, ebp
.text:004010E5                 pop     ebp
.text:004010E6                 retn
.text:004010E6 Base__Constructor endp

类Derived的默认构造函数与Base的类似,但是多了一个对Base的默认构造函数的调用:


.text:00401130 Derived__Constructor proc near          ; CODE XREF: sub_401000+6Ap
.text:00401130
.text:00401130 var_4           = dword ptr -4
.text:00401130
.text:00401130                 push    ebp
.text:00401131                 mov     ebp, esp
.text:00401133                 push    ecx
.text:00401134                 mov     [ebp+var_4], ecx
.text:00401137                 mov     ecx, [ebp+var_4]
.text:0040113A                 call    Base__Constructor
.text:0040113F                 mov     eax, [ebp+var_4]
.text:00401142                 mov     dword ptr [eax], offset off_40A190
.text:00401148                 mov     eax, [ebp+var_4]
.text:0040114B                 mov     esp, ebp
.text:0040114D                 pop     ebp
.text:0040114E                 retn
.text:0040114E Derived__Constructor endp

另外,我们也看一下类的结构:


class Base  size(4):
  +---
0  | {vfptr}
  +---

Base::$vftable@:
  | &Base_meta
  |  0
0  | &Base::demo
1  | &Base::demo_2

Base::demo this adjustor: 0
Base::demo_2 this adjustor: 0


class Derived  size(4):
  +---
  | +--- (base class Base)
0  | | {vfptr}
  | +---
  +---

Derived::$vftable@:
  | &Derived_meta
  |  0
0  | &Derived::demo
1  | &Derived::demo_2

Derived::demo this adjustor: 0
Derived::demo_2 this adjustor: 0

采用优化选项”/O2″后,反汇编得到的结果,这里也一并帖出:


.text:00401040 sub_401040      proc near               ; CODE XREF: start-5Cp
.text:00401040                 push    esi
.text:00401041                 push    4
.text:00401043                 call    new
.text:00401048                 add     esp, 4
.text:0040104B                 test    eax, eax
.text:0040104D                 jz      short loc_401059
.text:0040104F                 mov     dword ptr [eax], offset off_40A16C
.text:00401055                 mov     esi, eax
.text:00401057                 jmp     short loc_40105B
.text:00401059 ; ---------------------------------------------------------------------------
.text:00401059
.text:00401059 loc_401059:                             ; CODE XREF: sub_401040+Dj
.text:00401059                 xor     esi, esi
.text:0040105B
.text:0040105B loc_40105B:                             ; CODE XREF: sub_401040+17j
.text:0040105B                 mov     eax, [esi]
.text:0040105D                 mov     edx, [eax]
.text:0040105F                 mov     ecx, esi
.text:00401061                 call    edx
.text:00401063                 mov     eax, [esi]
.text:00401065                 mov     edx, [eax+4]
.text:00401068                 mov     ecx, esi
.text:0040106A                 call    edx
.text:0040106C                 push    offset aNonvirtualBase ; "Nonvirtual BASE DEMO 3\n"
.text:00401071                 call    sub_4010B2
.text:00401076                 push    4
.text:00401078                 call    new
.text:0040107D                 add     esp, 8
.text:00401080                 test    eax, eax
.text:00401082                 jz      short loc_40108E
.text:00401084                 mov     dword ptr [eax], offset off_40A190
.text:0040108A                 mov     esi, eax
.text:0040108C                 jmp     short loc_401090
.text:0040108E ; ---------------------------------------------------------------------------
.text:0040108E
.text:0040108E loc_40108E:                             ; CODE XREF: sub_401040+42j
.text:0040108E                 xor     esi, esi
.text:00401090
.text:00401090 loc_401090:                             ; CODE XREF: sub_401040+4Cj
.text:00401090                 mov     eax, [esi]
.text:00401092                 mov     edx, [eax]
.text:00401094                 mov     ecx, esi
.text:00401096                 call    edx
.text:00401098                 mov     eax, [esi]
.text:0040109A                 mov     edx, [eax+4]
.text:0040109D                 mov     ecx, esi
.text:0040109F                 call    edx
.text:004010A1                 push    offset aNonvirtualBase ; "Nonvirtual BASE DEMO 3\n"
.text:004010A6                 call    sub_4010B2
.text:004010AB                 add     esp, 4
.text:004010AE                 xor     eax, eax
.text:004010B0                 pop     esi
.text:004010B1                 retn
.text:004010B1 sub_401040      endp

发表评论