type
status
date
slug
summary
tags
category
icon
password
😀
本文旨在复习C/C++

📝Class-面向对象

thiscall调用约定

thiscall是唯一一个不能明确指明的函数修饰, 因为thiscall不是关键字. 它是C++类成员函数缺省的调用约定. 由于成员函数调用还有一个this指针, 因此必须特殊处理, thiscall意味着:
  • 参数从右向左入栈
  • 如果参数个数确定, this指针通过ecx传递给被调用者, 如果参数个数不确定, this指针在所有参数压栈后被压入堆栈
在这里我们先复习一下this指针
this指针存在于类的成员函数中,指向被调用函数所在的类实例的地址。
notion image
我们先在这里下断点,然后看反汇编
notion image
我们在内存这里查看我们自己定义的u1的地址,很显然是0x0019FF18
notion image
ebp-0x10的值为0x0019FF18,将u1的地址赋值给了ecx
notion image
这是第一个函数的内部
notion image
我们注意到它最后是自己清理堆栈的,而不是调用者,我们显示一下符号名,可以看到它pop出ecx后,将ecx存的地址赋值给了this指针
notion image

构造函数执行机制

局部对象

代码示例:
notion image
ecx里面存储的是mk的地址
notion image
我们首先运行的就是构造函数
notion image
我们把ecx取出来然后将ecx存的的地址给this
notion image
笔者在这里没有隐藏符号名,方便可以快速浏览出是什么意思
下图是笔者选择隐藏了符号名
notion image

堆对象

示例代码
notion image
构造函数
notion image

析构函数

与上面构造函数分析相似,这里不做过多展示

虚函数

有虚函数情况下的构造函数

示例代码:
构造函数
notion image

虚函数调用

notion image
构造函数,thiscall调用
setAge函数:把参数赋值给成员变量,这里要注意,对象地址的第一个位置是vftable,第一个成员变量的位置在4个字节后
notion image

有虚函数情况下的虚构函数

示例代码:
notion image
析构函数:这里把虚表拿出来,是为继承关系做准备,没继承关系则无事发生,有继承关系,需要把虚表指针指向对应的子类或父类

继承

单继承

示例代码:
主函数:主函数主要就两个地方,一个是构造函数,一个是成员函数的调用
notion image
构造函数:因为子类没有构造函数,所以这里就只调用了父类的构造函数
notion image
成员函数:调用父类函数,父类函数内部给对象第一个成员赋值,后面给子类成员变量赋值则是给对象地址第二个成员赋值,说明对象地址里按顺序依次存放的是父类成员,然后子类成员

派生多子类

示例代码
分析:
主函数:连续三个构造函数,然后连续三个speak函数调用,分别传入这三个对象的首地址
notion image
对象1的构造函数:取出对象首地址,调用父类构造函数,因为父类有虚函数,所以这里父类构造函数会给虚表赋值,因为子类重写父类虚函数,所以子类虚表覆盖对象首地址父类虚表
notion image
speak函数:从虚表里找到第二个函数,然后拿来调用,为什么是第二个函数呢,看源代码可以发现,子类成员方法有两个是虚方法,当前调用的这个是第二个声明的
notion image

多重继承

示例代码:
notion image
构造和析构的流程是相反的,这里的流程包括了执行顺序和对虚表的操作
  • 构造:先父类构造,再子类构造,然后把虚表全部覆盖成当前子类的
  • 析构:先把虚表全部替换成当前子类的,然后子类析构,再父类析构

子类对象转父类指针

示例代码:
notion image

总结

有虚函数的情况下,对象地址里首地址存储虚表指针
派生类的情况下,子类会依次调用父类的构造函数进行构造,然后再进行子类构造,如果父类有虚函数,则构造里会出现父类的虚函数
派生类的对象地址里会依次存放定义顺序父类成员最后才是当前派生类成员,里面会出现多个虚表,但都会被派生类的虚表覆盖
 
周报(二)Python-Capstone反汇编学习
Loading...
5m10v3
5m10v3
目前主攻方向为Re
Announcement
🎉5m10v3のBlog已经上线啦🎉
-- 感谢各位师傅的支持 ---
👏欢迎师傅们前来交流👏