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

同样的章节,示例44,由于我编译的情况与书本上略有差异,故在些记录一下。
区别在于:对Get_VTbl的调用,在我这里直接给赋值了。
试验平台:XP SP3,VS2008,命令行下编译,编译选项加上了优化选项“/O2”

书本上的示例代码如下(略有修改):


#include

class A{
  public:
    virtual void f(){
      printf("A_F\n");
    }
};

class B{
  public:
    virtual void f(){
      printf("B_F\n");
    }
    virtual void g(){
      printf("B_G\n");
    }
};

class C:public A,public B{
  public:
    void f(){
      printf("C_F\n");
    }
};

int main(){
  A *a=new A;
  B *b=new B;
  C *c=new C;
  
  a->f();
  b->f();
  b->g();
  c->f();
  c->g();
  
  return 0;
}

利用IDA5.2反汇编,自行分析一下后如下:


.text:00401050 sub_401050      proc near               ; CODE XREF: start-5Cp
.text:00401050                 push    ebx
.text:00401051                 push    esi
.text:00401052                 push    edi
.text:00401053                 push    4
.text:00401055                 call    new             ; 为实例分配内存
.text:0040105A                 add     esp, 4
.text:0040105D                 test    eax, eax        ; 测试内存分配是否成功
.text:0040105F                 jz      short loc_40106B
.text:00401061                 mov     dword ptr [eax], offset A_VTBL ;
.text:00401061                                         ; 分配成功后则直接赋一个值到EAX,
.text:00401061                                         ; 这个就是指指向VTBL的指针
.text:00401067                 mov     ebx, eax
.text:00401069                 jmp     short loc_40106D
.text:0040106B ; ---------------------------------------------------------------------------
.text:0040106B
.text:0040106B loc_40106B:                             ; CODE XREF: sub_401050+Fj
.text:0040106B                 xor     ebx, ebx
.text:0040106D
.text:0040106D loc_40106D:                             ; CODE XREF: sub_401050+19j
.text:0040106D                 push    4
.text:0040106F                 call    new
.text:00401074                 add     esp, 4
.text:00401077                 test    eax, eax
.text:00401079                 jz      short loc_401085
.text:0040107B                 mov     dword ptr [eax], offset B_VTBL ; 同上
.text:00401081                 mov     esi, eax
.text:00401083                 jmp     short loc_401087
.text:00401085 ; ---------------------------------------------------------------------------
.text:00401085
.text:00401085 loc_401085:                             ; CODE XREF: sub_401050+29j
.text:00401085                 xor     esi, esi
.text:00401087
.text:00401087 loc_401087:                             ; CODE XREF: sub_401050+33j
.text:00401087                 push    8
.text:00401089                 call    new
.text:0040108E                 add     esp, 4
.text:00401091                 test    eax, eax
.text:00401093                 jz      short loc_4010AD
.text:00401095                 mov     dword ptr [eax+4], offset B_VTBL ; B::f()
.text:0040109C                 mov     dword ptr [eax], offset ??_7C@@6BC@@@ ; C::f()
.text:004010A2                 mov     dword ptr [eax+4], offset C_VTBL ; 转向调用了401030处:
.text:004010A2                                         ; sub     ecx, 4
.text:004010A2                                         ; jmp     sub_401030
.text:004010A9                 mov     edi, eax
.text:004010AB                 jmp     short loc_4010AF
.text:004010AD ; ---------------------------------------------------------------------------
.text:004010AD
.text:004010AD loc_4010AD:                             ; CODE XREF: sub_401050+43j
.text:004010AD                 xor     edi, edi
.text:004010AF
.text:004010AF loc_4010AF:                             ; CODE XREF: sub_401050+5Bj
.text:004010AF                 mov     eax, [ebx]
.text:004010B1                 mov     edx, [eax]
.text:004010B3                 mov     ecx, ebx
.text:004010B5                 call    edx
.text:004010B7                 mov     eax, [esi]
.text:004010B9                 mov     edx, [eax]
.text:004010BB                 mov     ecx, esi
.text:004010BD                 call    edx
.text:004010BF                 mov     eax, [esi]
.text:004010C1                 mov     edx, [eax+4]
.text:004010C4                 mov     ecx, esi
.text:004010C6                 call    edx
.text:004010C8                 mov     eax, [edi]
.text:004010CA                 mov     edx, [eax]
.text:004010CC                 mov     ecx, edi
.text:004010CE                 call    edx
.text:004010D0                 mov     eax, [edi+4]
.text:004010D3                 mov     edx, [eax+4]
.text:004010D6                 lea     ecx, [edi+4]
.text:004010D9                 call    edx
.text:004010DB                 pop     edi
.text:004010DC                 pop     esi
.text:004010DD                 xor     eax, eax
.text:004010DF                 pop     ebx
.text:004010E0                 retn
.text:004010E0 sub_401050      endp

上面的分析略过了调用,下面是函数表:


.rdata:0040A150 ; class A;  [SI] O: 0, A: 0  (Class Informer)
.rdata:0040A150                 dd offset ??_R4A@@6B@   ; const A::`RTTI Complete Object Locator'
.rdata:0040A154 A_VTBL          dd offset sub_401000    ; DATA XREF: sub_401050+11o
.rdata:0040A154                                         ; A::f()
.rdata:0040A158 aA_f            db 'A_F',0Ah,0          ; DATA XREF: sub_401000o
.rdata:0040A15D                 align 10h
.rdata:0040A160 ;
.rdata:0040A160 ; class B;  [SI] O: 0, A: 0  (Class Informer)
.rdata:0040A160                 dd offset ??_R4B@@6B@   ; const B::`RTTI Complete Object Locator'
.rdata:0040A164 B_VTBL          dd offset sub_401010    ; DATA XREF: sub_401050+2Bo
.rdata:0040A164                                         ; sub_401050+45o
.rdata:0040A164                                         ; B::f()
.rdata:0040A168                 dd offset sub_401020    ; B::g()
.rdata:0040A16C aB_f            db 'B_F',0Ah,0          ; DATA XREF: sub_401010o
.rdata:0040A171                 align 4
.rdata:0040A174 aB_g            db 'B_G',0Ah,0          ; DATA XREF: sub_401020o
.rdata:0040A179                 align 4
.rdata:0040A17C ;
.rdata:0040A17C ; class C;  [MI] O: 4, A: 1  (Class Informer)
.rdata:0040A17C                 dd offset ??_R4C@@6BB@@@ ; const C::`RTTI Complete Object Locator'{for `B'}
.rdata:0040A180 C_VTBL          dd offset sub_401040    ; DATA XREF: sub_401050+52o
.rdata:0040A180                                         ; 转向调用了401030处:
.rdata:0040A180                                         ; sub     ecx, 4
.rdata:0040A180                                         ; jmp     sub_401030
.rdata:0040A184                 dd offset sub_401020    ; B::g()
.rdata:0040A188 ;
.rdata:0040A188 ; class C: A, B;  [MI] O: 0, A: 1  (Class Informer)
.rdata:0040A188                 dd offset ??_R4C@@6BC@@@ ; const C::`RTTI Complete Object Locator'{for `C'}
.rdata:0040A18C ; const C::`vftable'{for `C'}
.rdata:0040A18C ??_7C@@6BC@@@   dd offset sub_401030    ; DATA XREF: sub_401050+4Co
.rdata:0040A18C                                         ; C::f()
.rdata:0040A190 aC_f            db 'C_F',0Ah,0          ; DATA XREF: sub_401030o
.rdata:0040A195                 align 4
.rdata:0040A198 aBadAllocation  db 'bad allocation',0   ; DATA XREF: .data:0040D030o
.rdata:0040A198                                         ; .data:off_40D04Co ...
.rdata:0040A1A7                 align 4

这里同样验证了书上所说:
类C的虚函数表包含3个元素,从类B继承的虚函数f()的引用,但该元素又立即被编译器用C类的函数C::f()的形实转换程序给替换了。


.rdata:0040A180 C_VTBL          dd offset sub_401040    ; DATA XREF: sub_401050+52o
.rdata:0040A180                                         ; 转向调用了401030处:
.rdata:0040A180                                         ; sub     ecx, 4
.rdata:0040A180                                         ; jmp     sub_401030

发表评论