数组、结构体、类的反汇编

    本文主要主要研究C++中数组,结构以及类的反汇编。

1.数组

    数组在内存中式一块连续的区域。比如当声明char ch[100]的时候, 我们知道栈是向下增长的, 所以我们开辟地址空间的时候起地址就为[esp(esp会赋值给ebp) – 100, esp].我们可以看下如下的列子:

1 char buf[100];
2  for (int i = 0; i < 100; i++)
3 buf[i] = i;

我们看下他的反汇编代码:

1 char buf[100];
2 for (int i = 0; i < 100; i++)
3 00BD13A8 mov dword ptr [i],0
4 00BD13AF jmp wmain+3Ah (0BD13BAh)
5 00BD13B1 mov eax,dword ptr [i]
6 00BD13B4 add eax,1
7 00BD13B7 mov dword ptr [i],eax
8 00BD13BA cmp dword ptr [i],64h
9 00BD13BE jge wmain+4Ch (0BD13CCh) //到这里是一个典型的for循环标志了
10   buf[i] = i;
11 00BD13C0 mov eax,dword ptr [i] //把当前i的值赋予eax,这个eax是用来计算内存位置的
12  00BD13C3 mov cl,byte ptr [i] // 因为是char型,所以复制给cl, 这个是给内存赋值的
13  00BD13C6 mov byte ptr [ebp+eax-6Ch],cl //计算当前buf[i]在栈中的位置,并赋值
14  00BD13CA jmp wmain+31h (0BD13B1h)

    从上面我们就可以知道buf[0] = [ebp-100]; buf[1] = [ebp -99]……

2.结构体

    我们声明这样一个结构体

1 struct myStruct
2 {
3 int a;
4 char b;
5 float c;
6 };

    然后调用之:

1 int _tmain(int argc, _TCHAR* argv[])
2 {
3 int n = sizeof(myStruct);
4 n = sizeof(float);
5 myStruct test;
6 test.a = 0;
7 test.b = 'a';
8 test.c = 1.0f;
9 return 0;
10 }

    我们看下其内存是如何分布的:

1 int n = sizeof(myStruct);
2 00FB13A8 mov dword ptr [ebp-0Ch],0Ch
3 n = sizeof(float);
4 00FB13AF mov dword ptr [ebp-0Ch],4
5 myStruct test;
6 test.a = 0;
7 00FB13B6 mov dword ptr [ebp-20h],0
8 test.b = 'a';
9 00FB13BD mov byte ptr [ebp-1Ch],61h
10 test.c = 1.0f;
11 00FB13C1 fld1
12 00FB13C3 fstp dword ptr [ebp-18h]

    我们可以看出这个结构体的大小为OCH(12), float的大小为4, int为4, char为1, 考虑到内存对齐, 大小就得为4的整数倍, 所以为12。

        test.a 在内存中的位置为[ebp-20h];

        test.b 在内存中的位置为[ebp-2Ch];

        test.C 在内存中的位置为[ebp-28h];

3. 类

    C++中的类与结构体没有本质上的区别。都是在某一内存地址上开辟地址空间,存放和操作成员变量。我们可以看下如下的测试代码:

1 class myClass
2 {
3  private:
4 int m_a;
5 char m_b;
6 float m_c;
7  public:
8 myClass(){}
9 ~myClass(){}
10 void SetA(int a)
11 {
12 m_a = a;
13 }
14 virtual void SetB(char b)
15 {
16 m_b = b;
17 }
18 virtual void SetC(float c)
19 {
20 m_c = c;
21 }
22 };

    看下其反汇编的实现:

1 int n = sizeof(myClass);
2 0030144D mov dword ptr [ebp-14h],10h
3 myClass test;
4  00301454 lea ecx,[ebp-2Ch]
5  00301457 call myClass::myClass (301028h)
6 0030145C mov dword ptr [ebp-4],0
7 test.SetA(10);
8  00301463 push 0Ah
9  00301465 lea ecx,[ebp-2Ch]
10  00301468 call myClass::SetA (301014h)
11 test.SetB('a');
12 0030146D push 61h
13 0030146F lea ecx,[ebp-2Ch]
14  00301472 call myClass::SetB (3011EFh)
15 test.SetC(1.0f);
16  00301477 push ecx
17  00301478 fld1
18 0030147A fstp dword ptr [esp]
19 0030147D lea ecx,[ebp-2Ch]
20  00301480 call myClass::SetC (301104h)
21 return 0;
22  00301485 mov dword ptr [ebp-0F8h],0
23 0030148F mov dword ptr [ebp-4],0FFFFFFFFh
24  00301496 lea ecx,[ebp-2Ch]
25  00301499 call myClass::~myClass (3010BEh)
26 0030149E mov eax,dword ptr [ebp-0F8h]

    这里先稍微解释下其意思:

        # 0030144D  表明这个类的大小为16, 那位什么不是如上结构体的为12呢, 一问类中用到虚函数,所以就有一个指向虚函数列表的指针,其大小为4。

        # 00301457  变量调用了该类的构造函数

        # 00301468  调用了SetA

        # 00301472  调用了SetB

        # 00301499  调用了析构函数

    我们分别来看下着四个函数内部的实现。

(1) 构造函数

1 00301550 mov dword ptr [ebp-8],ecx
2  00301553 mov eax,dword ptr [this] //首先我们把this指针放入eax中
3 00301556 mov dword ptr [eax],offset myClass::`vftable' (306744h)  
//然后把虚函数列表的地址放入[eax]中
4 0030155C mov eax,dword ptr [this]

如上,我们可以看出此类的构造函数只是简单得把虚函数列表的指针指向[this]的地址。

(2) SetA

    这个函数是一个的成员函数,我们看下其是如何实现的

1 003015E3 mov eax,dword ptr [this]
2 003015E6 mov ecx,dword ptr [a]
3 003015E9 mov dword ptr [eax+4],ecx

    如上,可以看出很简单,把参数a的值服务[this + 4]这块地址,而这块地址保存的是成员变量m_a的值。

(3) SetB

    SetB是一个虚函数, 我们看下其实如何实现的:

 

1 00301633 mov eax,dword ptr [this]
2 00301636 mov cl,byte ptr [b]
3 00301639 mov byte ptr [eax+8],cl

 

   如上可以发现,虚函数的内部实现和普通的函数没有区别, 唯一不同的是虚函数的位置是放在一个类的虚函数列表里面的。

(4) 析构函数

    最后我们看下此类的析构函数是怎么实现的

 

1 003015A0 mov dword ptr [ebp-8],ecx
2 003015A3 mov eax,dword ptr [this]
3 003015A6 mov dword ptr [eax],offset myClass::`vftable' (306744h)

 

    因为我们在析构函数中什么事情也没有干,所以此析构函数只是简单的吧虚函数列表的地址放到[this]中。

    这里我总结下声明一个类其内存是如何分配的:

         # 当写下myStruct test;的时候会在栈上开辟一个内存空间,其地址为[this]

         # 如果此类有虚函数,就有有一个指向此类虚函数列表的指针,其地址为[this ]

         # m_a 的地址为[this +4]

         # m_b 的地址为[this + 8]

         # m_c 的地址为[this + 0Ch]

posted @ 2010-10-24 17:45  sld666666  阅读(2589)  评论(0编辑  收藏  举报