不知道大家有没有看过 陈浩的C++ 对象的内存布局(下),作者给的代码并不能运行
作者文章 :http://blog.csdn.net/haoel/article/details/3081328
我改过的代码如下 重点是这句
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <list>
using namespace std;
class B
{
public:
int ib;
char cb;
public:
B():ib(0),cb('B') {}
virtual void f() { cout << "B::f()" << endl;}
virtual void Bf() { cout << "B::Bf()" << endl;}
};
class B1 : virtual public B
{
public:
int ib1;
char cb1;
public:
B1():ib1(11),cb1('1') {}
virtual void f() { cout << "B1::f()" << endl;}
virtual void f1() { cout << "B1::f1()" << endl;}
virtual void Bf1() { cout << "B1::Bf1()" << endl;}
};
class B2: virtual public B
{
public:
int ib2;
char cb2;
public:
B2():ib2(12),cb2('2') {}
virtual void f() { cout << "B2::f()" << endl;}
virtual void f2() { cout << "B2::f2()" << endl;}
virtual void Bf2() { cout << "B2::Bf2()" << endl;}
};
class D : public B1, public B2
{
public:
int id;
char cd;
public:
D():id(100),cd('D') {}
virtual void f() { cout << "D::f()" << endl;}
virtual void f1() { cout << "D::f1()" << endl;}
virtual void f2() { cout << "D::f2()" << endl;}
virtual void Df() { cout << "D::Df()" << endl;}
};
void main()
{
D dd;
typedef void(*Fun)(void);
int** pVtab = NULL;
Fun pFun = NULL;
pVtab = (int**)ⅆ
cout << "[0] D::B1::_vptr->" << endl;
pFun = (Fun)pVtab[0][0];
cout << " [0] "; pFun(); //D::f1();
pFun = (Fun)pVtab[0][1];
cout << " [1] "; pFun(); //B1::Bf1();
pFun = (Fun)pVtab[0][2];
cout << " [2] "; pFun(); //D::Df();
pFun = (Fun)pVtab[0][3];
cout << " [3] ";
cout << pFun << endl;
//cout << pVtab[4][2] << endl;
cout << "[1] = 0x";
cout << (int*)((&dd)+1) <<endl; //????
cout << "[2] B1::ib1 = ";
cout << *((int*)(&dd)+2) <<endl; //B1::ib1
cout << "[3] B1::cb1 = ";
cout << (char)*((int*)(&dd)+3) << endl; //B1::cb1
//---------------------
cout << "[4] D::B2::_vptr->" << endl;
pFun = (Fun)pVtab[4][0];
cout << " [0] "; pFun(); //D::f2();
pFun = (Fun)pVtab[4][1];
cout << " [1] "; pFun(); //B2::Bf2();
pFun = (Fun)pVtab[4][2];
cout << " [2] ";
cout << pFun << endl;
cout << "[5] = 0x";
cout << *((int*)(&dd)+5) << endl; // ???
cout << "[6] B2::ib2 = ";
cout << (int)*((int*)(&dd)+6) <<endl; //B2::ib2
cout << "[7] B2::cb2 = ";
cout << (char)*((int*)(&dd)+7) << endl; //B2::cb2
cout << "[8] D::id = ";
cout << *((int*)(&dd)+8) << endl; //D::id
cout << "[9] D::cd = ";
cout << (char)*((int*)(&dd)+9) << endl;//D::cd
cout << "[10] = 0x";
cout << (int*)*((int*)(&dd)+10) << endl;
//---------------------
cout << "[11] D::B::_vptr->" << endl;
pFun = (Fun)pVtab[11][0];
int temp = 0;
__asm
{
mov temp, ecx //保存原始的ecx
}
//原始例子中注释掉 cout << " [0] ";这句就行,不注释的话也可以这样做
cout << " [0] "; //pFun(); //D::f();
//pFun();
__asm
{
mov ecx, temp //还原过来
}
pFun(); //这样就可以直接调用了
__asm
{
call pFun //继续汇编调用方法 简单直接call
}
//不用还原ecx 都可以直接调用 ,大家可以把上面的保护ecx操作注释掉试试
__asm
{
mov edx, pFun;
mov eax, [edx]
shr eax, 8 //调整偏移
add eax, 5
add edx, eax;
add edx, 3 //由于thunk 就是那个vdisp什么的,必须跳过 sub ecx, [ecx-4]这句
call edx
}
pFun = (Fun)pVtab[11][1];
cout << " [1] "; pFun(); //B::Bf();
pFun = (Fun)pVtab[11][2];
cout << " [2] ";
cout << pFun << endl;
cout << "[12] B::ib = ";
cout << *((int*)(&dd)+12) << endl; //B::ib
cout << "[13] B::cb = ";
cout << (char)*((int*)(&dd)+13) <<endl;//B::cb
}
运行结果如图
之所以要调过那个ecx-4是因为图形
估计这篇文章没人看 屌丝文章,就算了,不解释了 无非是调过这句 sub ecx,dword ptr[ecx-4] ,如果加了cout << "[0]"什么的 改了ecx,导致取ecx-4异常违规而已