类成员函数指针

来源:互联网 发布:天界五行进阶数据 编辑:程序博客网 时间:2024/05/01 17:06

如下代码:

#include "stdafx.h"class A {public:A():n(0xf1f1){}virtual ~A(){}virtual void show(){ printf("a"); }virtual void show1(){ printf("a1"); }void showA(){}private:int n;};class A0 {public:A0(){}virtual ~A0(){}virtual void show(){ printf("a0"); }virtual void show1(){ printf("a01"); }void showA0(){}};class B : public A , public A0 {public:B(){}virtual ~B(){}virtual void show(){ printf("b"); }virtual void show1(){ printf("b1"); }void showB(){}};typedef void (A0::*PFUNA0)();typedef void (B::*PFUNB)();int _tmain(int argc, _TCHAR* argv[]){printf("%p, %p\n", &A::show, &B::show);return 0;}
会发现&A::show==&B::show.


把_tmain改一下:

int _tmain(int argc, _TCHAR* argv[]){PFUNA0 lpProcA0 = (&A0::show1);A0 *lpa0 = &b0;(lpa0->*lpProcA0)();return 0;}
 反汇编:

; int __cdecl main(int argc, const char **argv, const char **envp).text:00401260 _main           proc near               ; CODE XREF: __tmainCRTStartup+10Ap.text:00401260.text:00401260 var_28          = dword ptr -28h.text:00401260 var_24          = dword ptr -24h.text:00401260 lpProcA0        = dword ptr -20h.text:00401260 lpa0            = dword ptr -1Ch.text:00401260 b0              = B ptr -18h.text:00401260 var_C           = dword ptr -0Ch.text:00401260 var_4           = dword ptr -4.text:00401260 argc            = dword ptr  8.text:00401260 argv            = dword ptr  0Ch.text:00401260 envp            = dword ptr  10h.text:00401260.text:00401260                 push    ebp.text:00401261                 mov     ebp, esp.text:00401263                 push    0FFFFFFFFh.text:00401265                 push    offset __ehhandler$_wmain.text:0040126A                 mov     eax, large fs:0.text:00401270                 push    eax.text:00401271                 sub     esp, 1Ch.text:00401274                 mov     eax, ___security_cookie.text:00401279                 xor     eax, ebp.text:0040127B                 push    eax.text:0040127C                 lea     eax, [ebp+var_C].text:0040127F                 mov     large fs:0, eax.text:00401285                 lea     ecx, [ebp+b0]   ; this.text:00401288                 call    ??0B@@QAE@XZ    ; B::B(void).text:0040128D                 mov     [ebp+var_4], 0.text:00401294                 mov     [ebp+lpProcA0], offset ??_9A0@@$B7AE ; [thunk]: A0::`vcall'{8,{flat}}.text:0040129B                 lea     eax, [ebp+b0].text:0040129E                 test    eax, eax.text:004012A0                 jz      short loc_4012AD.text:004012A2                 lea     ecx, [ebp+b0].text:004012A5                 add     ecx, 8.text:004012A8                 mov     [ebp+var_28], ecx.text:004012AB                 jmp     short loc_4012B4.text:004012AD ; ---------------------------------------------------------------------------.text:004012AD.text:004012AD loc_4012AD:                             ; CODE XREF: _main+40j.text:004012AD                 mov     [ebp+var_28], 0.text:004012B4.text:004012B4 loc_4012B4:                             ; CODE XREF: _main+4Bj.text:004012B4                 mov     edx, [ebp+var_28].text:004012B7                 mov     [ebp+lpa0], edx.text:004012BA                 mov     ecx, [ebp+lpa0].text:004012BD                 call    [ebp+lpProcA0].text:004012C0                 mov     [ebp+var_24], 0.text:004012C7                 mov     [ebp+var_4], 0FFFFFFFFh.text:004012CE                 lea     ecx, [ebp+b0]   ; this.text:004012D1                 call    ??1B@@UAE@XZ    ; B::~B(void).text:004012D6                 mov     eax, [ebp+var_24].text:004012D9                 mov     ecx, [ebp+var_C].text:004012DC                 mov     large fs:0, ecx.text:004012E3                 pop     ecx.text:004012E4                 mov     esp, ebp.text:004012E6                 pop     ebp.text:004012E7                 retn.text:004012E7 _main           endp
会发现编译器做了不少事情,简单总结如下:

1.修正虚函数表指针偏移

2.修正虚函数指针偏移

3.修正this指针

4.调用类成员函数


大概流程:

1.修正虚函数表指针:

.text:004012A5                 add     ecx, 8

2.跳转到&A0::show1地址处处,修正虚函数指针:

.text:00401300 ; [thunk]: __thiscall A0::`vcall'{8,{flat}}.text:00401300 ??_9A0@@$B7AE   proc near               ; DATA XREF: _main+34o.text:00401300                 mov     eax, [ecx].text:00401302                 jmp     dword ptr [eax+8].text:00401302 ??_9A0@@$B7AE   endp

[ecx]是修正后的虚函数表指针,然后跳到偏移为[eax + 8]处,即虚函数表第三项,但这项并不是show1的地址,而是这段代码:

3.修正this指针:

.text:004012F0 ; [thunk]:public: virtual void __thiscall B::show1`adjustor{8}' (void).text:004012F0 ?show1@B@@W7AEXXZ proc near             ; DATA XREF: .rdata:00402150o.text:004012F0                 sub     ecx, 8.text:004012F3                 jmp     ?show1@B@@UAEXXZ ; B::show1(void).text:004012F3 ?show1@B@@W7AEXXZ endp
这段代码主要是修正了一下ecx,即是将this指针指回b0。然后跳转到?show1@B@@UAEXXZ ; B::show1(void),这个才是B::show1的地址。

对this指针做修正是为了下来的函数能正确访问到b0的成员。(个人猜测,未验证)

这些都是和编译器相关的,cl.exe.





                                             
0 0
原创粉丝点击