首页
社区
课程
招聘
[旧帖] [原创](邀请码已发)c++多重继承时,分析内存数据分布 0.00雪花
发表于: 2010-2-16 19:18 1485

[旧帖] [原创](邀请码已发)c++多重继承时,分析内存数据分布 0.00雪花

2010-2-16 19:18
1485
题外话:该贴是我的第一帖,也是对最近学习c++的一点点学习总结。有不足之处望各位大大指正。
c++多重继承时,创建对象后内存数据可能含有如下几类数据:
1、类的成员数据  
2、指向虚表的首地址(4字节)  
3、指向跳表的首地址(4字节)

//代码开始
//例子代码如下:VC6.0环境下编译
class A
{
  public:
  virtual funA()
  {

  }
  int m_A;
};

class B
{
  public:
  virtual funB()
  {

  }
  int m_B;
};

class C
{
public:
  virtual funC()
  {

  }
  int m_C;
};

class D:virtual public A,public B,public C
{
public:
    virtual funD()
  {

  }

    int m_D;
};

//部分虚继承 内存分布
int main(int argc, char* argv[])
{
  D theD ;
  int nSizeA = sizeof(A); // 8字节
  int nSizeB = sizeof(B);  // 8字节
  int nSizeC = sizeof(C); // 8字节
  int nSizeD = sizeof(D); // 32字节 为什么D类只多了一个int成员数据,却8字节呢?
        // 答案在下面(就是因为D类多了一个指向跳表的指针)
  return 0;//此处下断点
}
//代码结束

目标:分析对象 theD  的内存格式。

开始分析:
1、在main函数里面,return语句前面下断点。
2、Watch 窗口获取如下数据
+  &theD    0x0012ff60
+  (B*)&theD  0x0012ff60
+  (C*)&theD  0x0012ff68
+  (A*)&theD  0x0012ff78
+  &theD.m_A  0x0012ff7c
+  &theD.m_B  0x0012ff64
+  &theD.m_C  0x0012ff6c
+  &theD.m_D  0x0012ff74

3、对以上获取的数据,根据地址大小进行排序。(也称该步骤为找空白)
   &theD    0x0012ff60
   (B*)&theD  0x0012ff60
   &theD.m_B  0x0012ff64
   (C*)&theD  0x0012ff68
   &theD.m_C  0x0012ff6c
  ?????????  0x0012ff70  
   &theD.m_D  0x0012ff74
   (A*)&theD  0x0012ff78
   &theD.m_A  0x0012ff7c
4、根据排序后发现0x0012ff70 地址处,空白(非我们的数据成员,但却在里面占用了空间),其实  

就是 跳表 的首地址。
  在内存中查看0x0012ff70地址的数据是 0x00422030 即跳表的首地址

5、以上地址的对应数据如下:
   &theD    0x0012ff60  0x00422024
   (B*)&theD  0x0012ff60  0x00422024  //B类首地址
   &theD.m_B  0x0012ff64  CCCCCCCC   //因为数据未初始化
   (C*)&theD  0x0012ff68  0x00422020  //C类首地址
   &theD.m_C  0x0012ff6c  CCCCCCCC
  ?????????  0x0012ff70  0x00422030   //跳表首地址
   &theD.m_D  0x0012ff74  CCCCCCCC
   (A*)&theD  0x0012ff78  0x0042201c  //A类首地址
   &theD.m_A  0x0012ff7c  CCCCCCCC
6、分析虚表指针指向的内容:
  (一)0x00422024 虚表分析
  00422024  1E 10 40 00    //即 0x0040101E
  00422028  2D 10 40 00  //即 0x0040102D

  打开反汇编窗口 ctrl+G  

  到该地址:0x0040101E
  @ILT+25(?funB@B@@UAEHXZ):
  0040101E   jmp         B::funB (004011b0)

  到该地址:0x0040102D
  @ILT+40(?funD@D@@UAEHXZ):
  0040102D   jmp         D::funD (00401210)

  (二)0x00422020 虚表分析
  00422020  28 10 40 00    //即 0x00401028

  打开反汇编窗口 ctrl+G   到该地址:0x00401028
  @ILT+35(?funC@C@@UAEHXZ):
  00401028   jmp         C::funC (004011e0)

  (三)0x0042201c 虚表分析
  0042201C  05 10 40 00    //即 0x00401005

  打开反汇编窗口 ctrl+G   到该地址:0x00401005
  @ILT+0(?funA@A@@UAEHXZ):
  00401005   jmp         A::funA (00401180)

7、分析跳表指针指向的内容:
  ?????????  0x0012ff70  0x00422030   //跳表首地址

  内存中查看 0x00422030 数据如下:
  00422030  F0 FF FF FF    //即 -0x10 负数 且发现0x0012ff70 - 0x10  = 0x0012ff60 ,B类首地址(B*)&theD
  00422034  08 00 00 00  //即 0x8   正数 且发现0x0012ff70 + 0x8   = 0x0012ff78 ,A类首地址(A*)&theD

8、根据以上的数据分析可以很容易得出D类对象的内存布局:
  vtableB = {B::funB, D::funD}        
  B::m_B;
  
  vtableC = C::funC
  C:m_C;
  
  虚基类偏移表 = { vtableB = -0x10 , vtableA = 0x08}
  
  D:m_D;

  vtableA = A::funA
  A:m_A; 

内存如此分布的原因(个人理解的观点),为了使基类指针指向子类对象时
,其内存的结构是和基类对象一样的。这样的话,就可以在首地址加上便宜去直接访问数据成员。

[课程]FART 脱壳王!加量不加价!FART作者讲授!

收藏
免费 0
支持
分享
最新回复 (5)
雪    币: 72
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
两三个星期前,有名同学也是写虚继承加虚表指针哦…获得邀请码喽…
但我想信你这些是自己调得,加油…
2010-2-16 23:00
0
雪    币: 40
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这些是自己写的,但都是上课老师那学的,再加上自己的一点理解,进行总结下
2010-2-16 23:23
0
雪    币: 424
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
关于这个可以去读读inside c++ object model
2010-2-16 23:49
0
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
5
不知道是学长还是同学,总之态度很好哟~
祝福你能拿到邀请码,嘿嘿
2010-2-17 02:35
0
雪    币: 40
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
你的学弟,老陈  O(∩_∩)O~  
2010-2-18 10:50
0
游客
登录 | 注册 方可回帖
返回
//