C++反汇编-结构体和类

学无止尽,积土成山,积水成渊-《C++反汇编与逆向分析技术揭秘》 读书笔记函数

对象的内存布局布局

 通常计算公式:优化

对象内存大小 = sizeof(数据成员1)+ sizeof(数据成员2) +. .. + sizeof(数据成员n)
 
若类中没有继承和虚函数的定义,还有三种特殊状况考虑:空类、内存对齐、静态成员函数。
  • 空类:空类的长度为1字节,若是不占用字节的话,this指针会悬空。考虑到类能够仅有成员函数,没有数据成员。
  • 内存对齐:在VC中,类和结构体中的数据成员是根据在类或结构中出现的顺序来依次申请空间的,因为内存对齐缘由,可能不会连续的排列,数据成员之间可能有间隙。
  • 静态变量:与静态全局变量相似,存在的位置和全局变量一致,只是编译器增长了做用域的检查,做用域以外不可见。
访问对象中的数据成员时,通常采用寄存器间接相对寻址,表达式esp±n±offset,或ebp±n±offset(其中esp±n或ebp±n是对象的首地址,offset 为数据成员相对对象首地址的偏移)。因为n和offset在编译阶段时属于常量,采用编译器优化时,表达式可能简化为 ebp±n 或 esp±n。

 

this指针this

this指针是保存所属对象的首地址。在调用成员函数时,遵循默认的thiscall约定,利用寄存器ECX保存对象的首地址(即this指针),以寄存器传参的方式传递到成员函数中,便是this指针的约定。成员函数中访问成员数据既是经过this指针间接访问的。
  • thiscall并不属于关键字,是C++成员函数特有的调用方式。
  • thiscall的参数压栈顺序也是从右至左
  • thiscall的栈平衡方式与_stdcall相同,由被调用方平衡。
  • 并非全部的this指针的传递都是经过寄存器ECX,能够强制改用其余调用方式(_如stdcall)
    1  class CTest
    2 {
    3  public:
    4       void __stdcall SetNumber( int nNumber){
    5                    m_nInt = nNumber;
    6            }
    7       int nNumber;
    8 }
使用thiscall调用方式的成员函数的要点分析
函数调用:
1  lea ecx, [mem]             ; 取对象地址
2  call FUN_ADDRESS           ; 调用成员函数
3      
函数内部:
1  mov XXX, ecx                    ; 发现函数内使用ecx中的数据,证实确是经过ecx来传递参数
2  mov [reg +  1], XXX

 

 
静态数据成员
静态数据成员和静态变量的原理相同,所以静态数据成员的初值会被写入编译连接后的执行文件中。当程序被加载时,操做系统将执行文件中的数据读到对应的内存单元中,静态数据成员便已经存在,而这时类并无实例对象。静态数据成员不属于某一个对象,与对象之间是多对一的关系。静态数据成员仅仅和类相关,和对象无关。
因此在计算某个类的对象所占用内存的大小,静态数据成员是不计算在内的。
 
区别:

 

  • 静态数据成员是常量地址,而普通数据成员通常存储在栈空间。
  • 静态成员经过当即数间接寻址访问,而普通数据成员通常经过寄存器相对间接寻址访问。
  • 静态成员访问时不须要this指针,而普通数据成员访问时须要使用this指针。

 

对象做为函数参数spa

 
对象做为函数参数,编译器会把对象视为由几个基本类型的数据的组合,和多个参数函数传参相似。类对象中的数据成员的传参顺序为:最早定义的数据成员最后压栈,最后定义的数据成员最早压栈。当类有构造函数和析构函数,过程会更复杂一些。因为对象在向函数传递过程当中,因为复制了对象,等同于又定义了一个对象,会调用复制构造函数。在函数退出时,复制的对象做为函数内部的局部变量被销毁,会调用析构函数。

 

 
对象做为返回值
 
对象做为函数返回值,与基本类型不一样。基本数据类型(双精度浮点数以及非标准的_int64类型除外)做为返回值时,经过寄存器EAX传递。对象做为返回值时,首先在 调用函数中申请返回对象使用的栈空间,而后将返回对象的首地址做为参数,经过 寄存器EAX传递给 被调用函数。在退出被调用函数时,将返回对象中的数据复制到 调用函数开辟的返回对象的栈空间,把返回对象的首地址经过寄存器EAX返回。返回的对象是临时存在的,也就是C++临时对象,做用域仅仅限于单条语句。
 
 1  class CReturn{
 2  public:
 3  int m_nNumber;
 4  in m_nArry[ 10];
 5 };
 6 CReturn GetCReturn()
 7 {
 8 CReturn RetObj;
 9 RetObj.m_nNumber =  0;
10  for( int i= 0; i<  10; i++)
11 {
12 RetObj.m_nArry[i] = i +  1;
13 }
14  return RetObj;
15 }
16  void main( int argc,  char *argv[])
17 {
18 CReturn objA;
19 objA = GetCReturn();
20 printf( " %d %d %d ", objA.m_nNumber, objA.m_nArry[ 0],  objA.m_nArry[ 9]);
21 }
相关文章
相关标签/搜索