学无止尽,积土成山,积水成渊-《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指针是保存所属对象的首地址。在调用成员函数时,遵循默认的thiscall约定,利用寄存器ECX保存对象的首地址(即this指针),以寄存器传参的方式传递到成员函数中,即是this指针的约定。成员函数中访问成员数据既是通过this指针间接访问的。
  • thiscall并不属于关键字,是C++成员函数特有的调用方式。
  • thiscall的参数压栈顺序也是从右至左
  • thiscall的栈平衡方式与_stdcall相同,由被调用方平衡。
  • 并不是所有的this指针的传递都是通过寄存器ECX,可以强制改用其他调用方式(_如stdcall)
     class CTest
    
          {
    
          public:
    
               void __stdcall SetNumber(int nNumber){
    
                             m_nInt = nNumber;
    
                     }
    
               int nNumber;
    
          }
    
使用thiscall调用方式的成员函数的要点分析
函数调用:
 lea ecx, [mem]            ;取对象地址

 call FUN_ADDRESS          ;调用成员函数

      

函数内部:

 mov XXX, ecx                   ;发现函数内使用ecx中的数据,证明确是通过ecx来传递参数

 mov [reg + ], XXX
 

静态数据成员

静态数据成员和静态变量的原理相同,因此静态数据成员的初值会被写入编译链接后的执行文件中。当程序被加载时,操作系统将执行文件中的数据读到对应的内存单元中,静态数据成员便已经存在,而这时类并没有实例对象。静态数据成员不属于某一个对象,与对象之间是多对一的关系。静态数据成员仅仅和类相关,和对象无关。
所以在计算某个类的对象所占用内存的大小,静态数据成员是不计算在内的。
 
区别:
  • 静态数据成员是常量地址,而普通数据成员一般存储在栈空间。
  • 静态成员通过立即数间接寻址访问,而普通数据成员一般通过寄存器相对间接寻址访问。
  • 静态成员访问时不需要this指针,而普通数据成员访问时需要使用this指针。

对象作为函数参数

 
对象作为函数参数,编译器会把对象视为由几个基本类型的数据的组合,和多个参数函数传参类似。类对象中的数据成员的传参顺序为:最先定义的数据成员最后压栈,最后定义的数据成员最先压栈。当类有构造函数和析构函数,过程会更复杂一些。由于对象在向函数传递过程中,由于复制了对象,等同于又定义了一个对象,会调用复制构造函数。在函数退出时,复制的对象作为函数内部的局部变量被销毁,会调用析构函数。
 
对象作为返回值
 
对象作为函数返回值,与基本类型不同。基本数据类型(双精度浮点数以及非标准的_int64类型除外)作为返回值时,通过寄存器EAX传递。对象作为返回值时,首先在调用函数中申请返回对象使用的栈空间,然后将返回对象的首地址作为参数,通过寄存器EAX传递给被调用函数。在退出被调用函数时,将返回对象中的数据复制到调用函数开辟的返回对象的栈空间,把返回对象的首地址通过寄存器EAX返回。返回的对象是临时存在的,也就是C++临时对象,作用域仅仅限于单条语句。
 
 1 class CReturn{

 2 public:

 3 int m_nNumber;

 4 in m_nArry[];

 5 };

 6 CReturn GetCReturn()

 7 {

 8 CReturn RetObj;

 9 RetObj.m_nNumber = ;

 for(int i=; i< ; i++)

 {

 RetObj.m_nArry[i] = i + ;

 }

 return RetObj;

 }

 void main(int argc, char *argv[])

 {

 CReturn objA;

 objA = GetCReturn();

 printf("%d %d %d", objA.m_nNumber, objA.m_nArry[],  objA.m_nArry[]);

 }
 

C++反汇编-结构体和类的更多相关文章

  1. (五)羽夏看C语言——结构体与类

    写在前面   由于此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇 ...

  2. C#中结构体和类的区别

    结构体和类同样能够定义字段,方法和构造函数,都能实例化对象,这样看来结构体和类的功能好像是一样的了,但是他们在数据的存储上是不一样的 C#结构体和类的区别问题:这两种数据类型的本质区别主要是各自指向的 ...

  3. Swift结构体与类

    在面向过程的编程语言(如C语言)中,结构体用得比较多,但是面向对象之后,如在C++和Objective-C中,结构体已经很少使用了.这是因为结构体能够做的事情,类完全可以取而代之.而Swift语言却非 ...

  4. C C++ 中结构体与类

    先来说说C和C++中结构体的不同 a) C语言中的结构体不能为空,否则会报错 1>d:\myproject\visual studio 2013\projects\myc++\main.c(71 ...

  5. 浅析C#中的结构体和类

    类和结构是 .NET Framework 中的常规类型系统的两种基本构造. 两者在本质上都属于数据结构.封装着一组总体作为一个逻辑单位的数据和行为. 数据和行为是该类或结构的"成员" ...

  6. 10 结构体和类 - —— 《Swift3.0 从入门到出家》

    Swift中的面向对象5个要素:枚举.结构体.类.协议.扩展 面向对象研究的是对象,完成一件事情需要多个对象参与,是生活的映射 Swift中结构体和类非常相似,也就是结构体能完成类的所有功能.结构体是 ...

  7. C++中 结构体和类的异同

    在C++中,结构体是一种特殊形态的类. 结构体和类的唯一区别就是:  结构体和类具有不同的默认访问控制属性. 类中,对于未指定访问控制属性的成员,其访问控制属性为私有类型(private) 结构体中, ...

  8. 介绍C#结构体与类区别

    1. 结构体与类定义方式 结构体定义使用struct类定义使用class 结构体: struct testDemo{ int num; void action(){ } } 类: class test ...

  9. C#中结构体与类的区别

    一.结构体和类非常相似 1,定义和使用非常相似,例子如下:public struct Student{    string Name;    int Age;}public class Questio ...

随机推荐

  1. python网络编程--事件驱动模型

    论事件驱动与异步IO 事件驱动模型:根据事件的触发去干什么事,就是根据一个事件做反应 原文:http://www.cnblogs.com/alex3714/articles/5248247.html常 ...

  2. Java 容器的基本概念

    java容器类类库的用途时"保存对象",并将其划分为两个不同的概念: 1)Collection(采集).一个独立元素的序列,这些元素都服从一条或多条规则,List必须按照插入的顺序 ...

  3. Sql Server2005 Transact-SQL 新兵器学习总结之-排名函数

    Transact-SQL提供了4个排名函数: rand() , dense_rand() , row_number() , ntile() 下面是对这4个函数的解释:rank() 返回结果集的分区内每 ...

  4. MySQL学习笔记:regexp正则表达式

    在MySQL中,模糊搜索的时候主要用两种方式: 1.like2.regexp + 正则表达式 性能优于like 正则表达式描述了一组字符串. 最简单的正则表达式是不含任何特殊字符的正则表达式.例如,正 ...

  5. MySQL学习笔记:date_add

    date_add函数 作用:date_add()函数向日期添加指定的时间间隔 语法: date_add(date,INTERVAL expr type) date:日期表达式 type:时间间隔,da ...

  6. windows环境下的heap spray+stack pivot gadget 实现绕过dep

    ASLR+DEP是windows平台下最为常见的两种保护手段.这两种手段使得最基础的jmp esp等手法不再适用,而单纯的堆喷也会因为堆内存不可执行而失效.那么这里就来介绍一下heap spray+s ...

  7. RabbitMQ介绍及安装部署

    本节内容: RabbitMQ介绍 RabbitMQ运行原理 RabbitMQ重要术语 三种ExchangeType RabbitMQ集群种类 集群基本概念 镜像模式部署集群 一.RabbitMQ介绍 ...

  8. openfire 部署后报错: java.lang.IllegalArgumentException: interface xx is not visible from class loader

    该异常是创建代理时加载接口的类加载器与创建时传入的不一致. 在本地eclipse做openfire二次开发,本地运行没错,部署到服务器上后报异常:  java.lang.IllegalArgument ...

  9. 牛客练习赛1 B - 树

    链接:https://www.nowcoder.com/acm/contest/2/B来源:牛客网 题目描述 shy有一颗树,树有n个结点.有k种不同颜色的染料给树染色.一个染色方案是合法的,当且仅当 ...

  10. 那些年我们爬过的山 - mybatis批量导入

    [原创作品,转载请注明出处] 写这篇文章之前想着给这篇博客起一个文艺一点的标题,思来想去,想到了那些年我们爬过的山,或者我们一起趟过的河?代码不规范,同事两行泪,这是多么痛的领悟啊! 背景 本组一名实 ...