首页 > 编程语言 >C++逆向分析——构造函数和析构函数

C++逆向分析——构造函数和析构函数

时间:2023-06-02 20:05:35浏览次数:38  
标签:FF 00 函数 int C++ Student 和析构 构造函数

构造函数与析构函数

构造函数

struct Student {

int a;


int b;

 
 Student() {

 printf("Look.");

 }
 

void Init(int a, int b) {


this->a = a;


this->b = b;

 }
 
};

如上代码中,我们发现了存在一个函数,这个函数没有返回类型并且与结构体名称一样,那这段函数在什么时候执行呢?

我们先不使用之前学习的方法去调用,直接创建一个对象,这时候会发现该函数就直接执行了:

C++逆向分析——构造函数和析构函数_4D

这个函数,我们就称之为构造函数。==》在汇编看来,这个构造函数和任何函数没有区别!

它的汇编代码如下:

C++逆向分析——构造函数和析构函数_构造函数_02

 

贴下我vs2022里的汇编代码:

struct Student {
	int a;
	int b;

	Student() {
01001770 55                   push        ebp  
01001771 8B EC                mov         ebp,esp  
01001773 81 EC CC 00 00 00    sub         esp,0CCh  
01001779 53                   push        ebx  
0100177A 56                   push        esi  
0100177B 57                   push        edi  
0100177C 51                   push        ecx  
0100177D 8D 7D F4             lea         edi,[ebp-0Ch]  
01001780 B9 03 00 00 00       mov         ecx,3  
01001785 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
0100178A F3 AB                rep stos    dword ptr es:[edi]  
0100178C 59                   pop         ecx  
0100178D 89 4D F8             mov         dword ptr [this],ecx  
01001790 B9 08 C0 00 01       mov         ecx,offset _F4F12A98_Conso@cpp (0100C008h)  
01001795 E8 81 FB FF FF       call        @__CheckForDebuggerJustMyCode@4 (0100131Bh)  
		printf("Look.");
0100179A 68 D0 7B 00 01       push        offset string "Look." (01007BD0h)  
0100179F E8 29 F9 FF FF       call        _printf (010010CDh)  
010017A4 83 C4 04             add         esp,4  
	}
010017A7 8B 45 F8             mov         eax,dword ptr [this]  
010017AA 5F                   pop         edi  
010017AB 5E                   pop         esi  
010017AC 5B                   pop         ebx  
010017AD 81 C4 CC 00 00 00    add         esp,0CCh  
010017B3 3B EC                cmp         ebp,esp  
010017B5 E8 85 FA FF FF       call        __RTC_CheckEsp (0100123Fh)  
010017BA 8B E5                mov         esp,ebp  
010017BC 5D                   pop         ebp  
010017BD C3                   ret

 

 

如果我们想要在创建对象的时候,自定义初始化成员的值,就可以在析构函数上加上参数:

struct Student {

int a;


int b;

 

 Student(int a, int b) {


this->a = a;


this->b = b;

 }
 

void Init(int a, int b) {


this->a = a;


this->b = b;

 }
 
};
 

void main() {


 Student s(1, 2);

 

return;

}

创建对象的时候,在对象名后面加上括号传入即可;但是这样就会存在一个问题,我们不想初始化值的时候就没有办法创建这个类:

struct Student {

int a;


int b;

 

 Student(int a, int b) {


this->a = a;


this->b = b;

 }
 

void Init(int a, int b) {


this->a = a;


this->b = b;

 }
 
};
 

void main() {

 Student s;
 

return;

}

编译直接出错:

C++逆向分析——构造函数和析构函数_4D_03

这是因为编译器发现你没有传入参数,就会去寻找没有参数的构造函数,但是在这段代码中没有声明,所以需要声明一下:

#include <stdio.h>
struct Student {

int a;


int b;

 
 Student() {

 printf("Look.");

 }
 

 Student(int a, int b) {


this->a = a;


this->b = b;

 }
 

void Init(int a, int b) {


this->a = a;


this->b = b;

 }
 
};
 

void main() {

 Student s;
 

return;

}

这样就没有任何问题了,你想传参就传,不想就不传。

我们总结一下其(构造函数)特点

  1. 构造函数名称与类名一样
  2. 不能写返回类型(无返回值)==》严格说,vs底层反汇编是设置eax为this指针,汇编码为:mov         eax,dword ptr [this]


  3. 创建对象时,则会自动调用执行,一般用于初始化
  4. 可以有多个构造函数(建议只有一个无参的),这种声明方式我们称之为重载(其他函数也可以)
  5. 编译器不要求必须提供构造函数

 

上面黄色部分的观点补充:

C++逆向分析——构造函数和析构函数_4D_04

结合前面博客this指针的讲解,书中也给出了一个例子,如下:

C++逆向分析——构造函数和析构函数_构造函数_05

 

 

 

析构函数

析构函数函数的语法跟构造函数很像,其区别就是:析构函数需要在函数名前面加一个波浪号析构函数只能有一个析构函数函数不可以写参数构造函数是创建对象的时候执行,但是析构函数函数是在对象销毁前执行

#include <stdio.h>
struct Student {

int a;


int b;

 
 Student() {

 printf("Look.");

 }
 

 Student(int a, int b) {


this->a = a;


this->b = b;

 }
 
 ~Student() {

 printf("Look A.");

 }
 

void Init(int a, int b) {


this->a = a;


this->b = b;

 }
 
};
 

void main() {

 Student s;
 

return;

}

析构函数函数是在对象销毁前执行,那么对象会在什么时候销毁呢?可以看下反汇编代码:

C++逆向分析——构造函数和析构函数_析构函数_06

在我的vs2022编译代码里,看到的反汇编码:

Student s;
0012194F 8D 4D F0             lea         ecx,[s]  
00121952 E8 5F FA FF FF       call        Student::Student (01213B6h)  

	return;
00121957 8D 4D F0             lea         ecx,[s]  
0012195A E8 61 FA FF FF       call        Student::~Student (01213C0h)  
}


	~Student() {	
00121FC0 55                   push        ebp  
00121FC1 8B EC                mov         ebp,esp  
00121FC3 81 EC CC 00 00 00    sub         esp,0CCh  
00121FC9 53                   push        ebx  
00121FCA 56                   push        esi  
00121FCB 57                   push        edi  
00121FCC 51                   push        ecx  
00121FCD 8D 7D F4             lea         edi,[ebp-0Ch]  
00121FD0 B9 03 00 00 00       mov         ecx,3  
00121FD5 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00121FDA F3 AB                rep stos    dword ptr es:[edi]  
00121FDC 59                   pop         ecx  
00121FDD 89 4D F8             mov         dword ptr [this],ecx  
00121FE0 B9 08 C0 12 00       mov         ecx,offset _F4F12A98_Conso@cpp (012C008h)  
00121FE5 E8 31 F3 FF FF       call        @__CheckForDebuggerJustMyCode@4 (012131Bh)  
		printf("Look A.");
00121FEA 68 D8 7B 12 00       push        offset string "Look A." (0127BD8h)  
00121FEF E8 D9 F0 FF FF       call        _printf (01210CDh)  
00121FF4 83 C4 04             add         esp,4  
	}

 注意,也通过ecx传递了一个this指针进去。

------

 

会发现在程序执行结束,也就是main函数的return之后会执行析构函数函数,但这句话实际上是不严谨的,因为我们的main函数是没有返回值的,也就是return不会有对应的汇编代码,当我们设置返回值再来看下反汇编代码:

#include <stdio.h>
struct Student {

int a;


int b;

 
 Student() {

 printf("Look.");

 }
 

 Student(int a, int b) {


this->a = a;


this->b = b;

 }
 
 ~Student() {

 printf("Look A.");

 }
 

void Init(int a, int b) {


this->a = a;


this->b = b;

 }
 
};
 

int main() {

 Student s;
 

return0;

}

C++逆向分析——构造函数和析构函数_构造函数_07

可以很清晰的看见,析构函数是在return返回之前执行的。

我们总结(析构函数)一下:

  1. 只能有一个,不支持重载
  2. 无返回值
  3. 无任何参数
  4. 主要用于清理工作
  5. 编译器不要求必须提供
  6. 当对象在main函数(堆栈)中创建,在return之前调用执行;当对象在全局变量区,则会在应用程序退出之前调用

标签:FF,00,函数,int,C++,Student,和析构,构造函数
From: https://blog.51cto.com/u_11908275/6404729

相关文章

  • Mac在VSCode中搭建CC++环境
    Mac在VSCode中搭建C/C++环境https://www.jianshu.com/p/050fa455bc74利用VScode和cmake编译构建C++工程代码https://m.oldpan.me/archives/use-vscode-cmake-tools-build-projectVSCode开发C在Mac的配置https://www.jianshu.com/p/014e6e2c97e2选择C/Cpp:EditConfiguration......
  • 2016第七届蓝桥杯国赛决赛c/c++本科B组试题总结及解题答案
    未完待更新........1.一步之遥从昏迷中醒来,小明发现自己被关在X星球的废矿车里。矿车停在平直的废弃的轨道上。他的面前是两个按钮,分别写着“F”和“B”。小明突然记起来,这两个按钮可以控制矿车在轨道上前进和后退。按F,会前进97米。按B会后退127米。 透过昏暗的灯光,小明看......
  • C++字符串分割和C语言常用格式控制
    C++string的输出格式控制输出一个字符串:左对齐,字宽为10,空格填充1.strings;2.cin>>s;3.cout<<std::left<<setw(10)<<setfill('*')<<s<<endl;输入:love输出效果:love******C++string字符流字符分割技巧输入一行字符串,然后按某个字符分割成若干子串1.strings;......
  • c++ libcurl获取http header信息
    boolHttpDownloader::GetReceiveHeaderInfo(conststd::string&strUrl,std::map<std::string,std::string>&mapHeaderKeyValue){boolbRet=false;if(strUrl.empty()){returnbRet;}else{CURL*handl......
  • 通过定义私有构造函数限制类的实例化
    当在一个类中定义了私有构造函数时,它将限制其他代码在类外部直接实例化该类的对象。这意味着除了类内部的代码,其他代码无法通过调用类的构造函数来创建类的实例。通过定义私有构造函数,可以实现以下几个方面的控制:防止类被意外地实例化:私有构造函数可以确保类的实例化只能在类......
  • C++ break 语句
    C++中 break 语句有以下两种用法:当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。它可用于终止 switch 语句中的一个case。如果您使用的是嵌套循环(即一个循环内嵌套另一个循环),break语句会停止执行最内层的循环,然后开始执......
  • C++ goto 语句
    goto 语句允许把控制无条件转移到同一函数内的被标记的语句。注意:在任何编程语言中,都不建议使用goto语句。因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改。任何使用goto语句的程序可以改写成不需要使用goto语句的写法。https://www.81rz.com/zjxt65/......
  • C++ continue 语句
    C++中的 continue 语句有点像 break 语句。但它不是强迫终止,continue会跳过当前循环中的代码,强迫开始下一次循环。对于 for 循环,continue 语句会导致执行条件测试和循环增量部分。对于 while 和 do...while 循环,continue 语句会导致程序控制回到条件测试上。https......
  • uobject只有可以声明无参构造函数和不写构造函数
    (一)结论:(二)测试过程:第一种:不声明任何构造函数:第二种:声明默认构造函数:第三种:声明其他构造函数:(直接报错,需要声明默认构造)(三)ue实现原理:UHT里可以解析出你是否定义了构造函数,是哪种构造函数:参数是否匹配“FObjectInitializer”:不同构造函数,对应使用不同的宏定义: 链接:ht......
  • C++高级编程
    文章目录C++文件和流打开文件关闭文件写入文件读取文件读取&写入实例文件位置指针C++异常处理抛出异常捕获异常C++标准的异常定义新的异常动态内存new和delete运算符数组的动态内存分配对象的动态内存分配C++命名空间定义命名空间using指令不连续的命名空间嵌套的命名空间关于命名......