【逆向】03-20扩大节 c++代码完成 ;类当作函数参数却调用了析构函数疑难分析

这篇具有很好参考价值的文章主要介绍了【逆向】03-20扩大节 c++代码完成 ;类当作函数参数却调用了析构函数疑难分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

若要看PE结构操作最新代码,点击主页查看!!

 文章来源地址https://www.toymoban.com/news/detail-729658.html

和上一节的代码相比,本文章主要修复了上一篇文章代码中PE类中的Analyze函数,这样不管是Before_Stretch_Data还是Stretch_Data,Shrink_Data,在这个函数中都可以分析出PE结构

另外新添加了函数Expand_Section函数,可以自动扩大最后一个节,并写入新的文件中,亲测可以使用,程序可以完美运行
Expand_Section函数的思路就是
 

扩大节:

只能扩大最后一个节

  • 1.拉伸到内存

  • 2.分配一块新的空间,SizeOfImage + Ex(扩大出来的空间)

  • 3.将最后一个节的SizeOfRawData和VirtualSize改成N SizeOfRawData=VirtualSize=N N=(原来的SizeOfRawData和VirtualSize两者比较大的那一个内存对齐后的值)+Ex

  • 4.修改SizeOfImage大小 SizeOfImage=SizeOfImage+Ex

 

期间我遇到一个百思不得其解的问题:
就是我将一个类作为参数继续函数传值,但是程序运行报错了,但是如果我传的是引用却不会报错。在文章末尾说

上代码先:
 

#include <windows.h>
#include <iostream>
#include <string>

#include <malloc.h>
using namespace std;

int MAX(int a, int b)
{
	return a >= b ? a : b;
}

class Data
{
public:
	PIMAGE_DOS_HEADER my_dos;//dos头结构
	PIMAGE_FILE_HEADER my_file;//file结构
	PIMAGE_OPTIONAL_HEADER32 my_optional;//可选PE头结构
	PIMAGE_SECTION_HEADER* my_section ;//节表结构


	void* Before_Stretch_Data ; //指向拉伸前的内容
	void* Stretch_Data ; //指向拉伸后的内容
	void* Shrink_Data ; //指向缩小PE结构的内容

	Data()
	{
		my_dos = nullptr;//dos头结构
		my_file = nullptr;//file结构
		my_optional = nullptr;//可选PE头结构
		my_section = nullptr;//节表结构


		Before_Stretch_Data = nullptr; //指向拉伸前的内容
		Stretch_Data = nullptr; //指向拉伸后的内容
		Shrink_Data = nullptr; //指向缩小PE结构的内容
	}

	~Data()
	{
		if (Before_Stretch_Data != nullptr)
		{
			free(Before_Stretch_Data);
			Before_Stretch_Data = nullptr;
		}

		if (Stretch_Data != nullptr)
		{
			free(Stretch_Data);
			Stretch_Data = nullptr;
		}

		if (Shrink_Data != nullptr)
		{
			free(Shrink_Data);
			Shrink_Data = nullptr;
		}
	}


	void Copy_Before_Strectch_Data(Data my_data); //只深拷贝Before_Strectch_Data
};

void Data::Copy_Before_Strectch_Data(Data my_data)
{
	int size=_msize(my_data.Before_Stretch_Data);
	memcpy_s(this->Before_Stretch_Data, size, my_data.Before_Stretch_Data, size);
}



class PE
{
public:




public:
	void Readfile(char* filename, Data& my_data);  //读取pe文件

	void Analyze_PE(Data& my_data);  //分析pe结构
	
	void Stretch_PE(Data& my_data);  //拉伸pe结构

	void Shrink_PE(Data& my_data); //缩小pe结构

	void New_Section(char* filename,Data& my_data);//新增节,非扩大节,并写入新的exe文件中

	void Expand_Section(Data& my_data, char* filename);  //扩大节

	int Section_Align(int temp,Data& my_data); //返回内存对齐后的大小

	int File_Align(int temp,Data& my_data); //返回文件对齐后的大小

	void Copy_Data(Data& my_data);
};

void PE:: Expand_Section(Data& my_data,char* filename)
{
	this->Stretch_PE(my_data);
	unsigned Size = 0;//扩大节后新的文件大小
	Size = my_data.my_optional->ImageBase + Section_Align(MAX(my_data.my_section[0]->SizeOfRawData, my_data.my_section[0]->Misc.VirtualSize),my_data);

	Data Expand_Data;
	Expand_Data.Stretch_Data= (void*)malloc(Size);
	memset(Expand_Data.Stretch_Data, 0, Size);
	memcpy_s(Expand_Data.Stretch_Data, _msize(my_data.Stretch_Data), my_data.Stretch_Data, _msize(my_data.Stretch_Data));

	Analyze_PE(Expand_Data);

	Expand_Data.my_section[my_data.my_file->NumberOfSections - 1]->SizeOfRawData = Section_Align(MAX(my_data.my_section[0]->SizeOfRawData, my_data.my_section[0]->Misc.VirtualSize), my_data) + Section_Align(MAX(my_data.my_section[my_data.my_file->NumberOfSections - 1]->SizeOfRawData, my_data.my_section[my_data.my_file->NumberOfSections - 1]->Misc.VirtualSize), my_data);
	Expand_Data.my_section[my_data.my_file->NumberOfSections - 1]->Misc.VirtualSize = Expand_Data.my_section[my_data.my_file->NumberOfSections - 1]->SizeOfRawData;

	Expand_Data.my_optional->SizeOfImage += Section_Align(MAX(my_data.my_section[0]->SizeOfRawData, my_data.my_section[0]->Misc.VirtualSize), my_data);

	void* Temp_Ptr = (char*)Expand_Data.Stretch_Data+ Expand_Data.my_section[Expand_Data.my_file->NumberOfSections - 1]->VirtualAddress+ Section_Align(MAX(my_data.my_section[Expand_Data.my_file->NumberOfSections - 1]->SizeOfRawData, my_data.my_section[Expand_Data.my_file->NumberOfSections - 1]->Misc.VirtualSize),my_data);
	int temp_size = Section_Align(MAX(my_data.my_section[0]->SizeOfRawData, my_data.my_section[0]->Misc.VirtualSize), my_data);
	void* Temp_Ptr2 = (char*)my_data.Stretch_Data + my_data.my_section[0]->VirtualAddress;

	memcpy_s(Temp_Ptr, temp_size, Temp_Ptr2, temp_size);


	Shrink_PE(Expand_Data);

	FILE* my_file;
	if (fopen_s(&my_file, filename, "wb") != 0)
	{
		cout << "打开文件失败!" << endl;
		
	}
	else
	{
		Size = _msize(Expand_Data.Shrink_Data);
		fwrite(Expand_Data.Shrink_Data, 1, Size, my_file);
		cout << "写入成功!" << endl;
	}

}


int PE::Section_Align(int temp, Data& my_data)
{
	return (temp / my_data.my_optional->SectionAlignment)* my_data.my_optional->SectionAlignment + my_data.my_optional->SectionAlignment;
}

int PE::File_Align(int temp, Data& my_data)
{
	return temp / my_data.my_optional->FileAlignment + my_data.my_optional->FileAlignment;
}

void PE::New_Section(char* filename, Data& my_data)
{
	unsigned int Size; //Size是新文件的大小,是原来的文件大小加上.VirtualSize和SizeOfRawData较大的那个
	Size = my_data.my_optional->SizeOfHeaders;
	for (int i = 0;i < my_data.my_file->NumberOfSections; i++)
	{
		Size += my_data.my_section[i]->SizeOfRawData;
	}
	Size+= my_data.my_section[0]->SizeOfRawData;//这是最终新的文件的大小

	Data New_Data;
	New_Data.Before_Stretch_Data = (void*)malloc(Size*1);
	memset(New_Data.Before_Stretch_Data, 0, Size);
	memcpy_s(New_Data.Before_Stretch_Data, Size, my_data.Before_Stretch_Data, Size - my_data.my_section[0]->SizeOfRawData);//将原来的文件复制过来

	Analyze_PE(New_Data);//让New_Data的dos,file,optional,section有数据
	
	//复制新的节表
	void* Temp_ptr1 = (char*)my_data.Before_Stretch_Data + 0x98 + my_data.my_file->SizeOfOptionalHeader;
	void* Temp_ptr2 = (char*)New_Data.Before_Stretch_Data + 0x98 + my_data.my_file->SizeOfOptionalHeader + my_data.my_file->NumberOfSections * 0x28;
	memcpy_s(Temp_ptr2, 0x28, Temp_ptr1, 0x28);
	//复制新的节
	Temp_ptr1 = (char*)my_data.Before_Stretch_Data + my_data.my_optional->SizeOfHeaders;//指向.text段
	Temp_ptr2 = (char*)New_Data.Before_Stretch_Data + Size - my_data.my_section[0]->SizeOfRawData;

	memcpy_s(Temp_ptr2, my_data.my_section[0]->SizeOfRawData, Temp_ptr1, my_data.my_section[0]->SizeOfRawData);//复制完.text段作为新增节

	//接下来要改Header的各项数据
	New_Data.my_file->NumberOfSections++;
	New_Data.my_optional->SizeOfImage += my_data.my_section[0]->SizeOfRawData;

	Analyze_PE(New_Data);
	New_Data.my_section[New_Data.my_file->NumberOfSections - 1]->PointerToRawData = New_Data.my_section[New_Data.my_file->NumberOfSections - 2]->PointerToRawData + New_Data.my_section[New_Data.my_file->NumberOfSections - 2]->SizeOfRawData;
	int size;
	if (New_Data.my_section[New_Data.my_file->NumberOfSections - 2]->Misc.VirtualSize >= New_Data.my_section[New_Data.my_file->NumberOfSections - 2]->SizeOfRawData)
	{
		size = New_Data.my_section[New_Data.my_file->NumberOfSections - 2]->Misc.VirtualSize;
	}
	else
	{
		size = New_Data.my_section[New_Data.my_file->NumberOfSections - 2]->SizeOfRawData;
	}
	size = size / my_data.my_optional->SectionAlignment + my_data.my_optional->SectionAlignment;
	New_Data.my_section[New_Data.my_file->NumberOfSections - 1]->VirtualAddress = New_Data.my_section[New_Data.my_file->NumberOfSections - 2]->VirtualAddress+size;

	FILE* my_file;
	if (fopen_s(&my_file, filename, "wb") == 0)
	{
		fwrite(New_Data.Before_Stretch_Data, 1, Size, my_file);
		cout << "写入成功!" << endl;
		return;
	}
	else
	{
		cout << "打开文件失败" << endl;
		return;
	}
}


void PE::Readfile(char* filename,Data& my_data)
{
	unsigned int size;
	FILE* datafile;
	void* data;
	//打开文件
	if (fopen_s(&datafile, filename, "rb") != 0)
	{
		cout << "打开文件失败" << endl;
		return;
	}


	else
	{
		//获取文件的大小
		cout << "打开文件成功!" << endl;
		fseek(datafile, 0, SEEK_END);
		size = ftell(datafile);
		fseek(datafile, 0, SEEK_SET);
		if (size == -1L)
		{
			cout << "文件大小判断失败!" << endl;
			return;
		}

		//申请内存空间把文件内容保存下来
		my_data.Before_Stretch_Data = (void*)malloc(size * sizeof(char));

		if (fread_s(my_data.Before_Stretch_Data, size, sizeof(char), size, datafile) == 0)
		{
			cout << "写入数据失败!" << endl;
			return;
		}
		cout << "写入数据成功,成功获取Data!" << endl;
		return ;
	}

}

//分析PE结构
void PE::Analyze_PE(Data& my_data)
{
	if (my_data.Before_Stretch_Data != nullptr)
	{
		DWORD* Temp_ptr = (DWORD*)my_data.Before_Stretch_Data;
		my_data.my_dos = (PIMAGE_DOS_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)my_data.Before_Stretch_Data + my_data.my_dos->e_lfanew);
		Temp_ptr++;
		my_data.my_file = (PIMAGE_FILE_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)Temp_ptr + 0x14);
		my_data.my_optional = (PIMAGE_OPTIONAL_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)my_data.my_optional + my_data.my_file->SizeOfOptionalHeader);
		my_data.my_section = (PIMAGE_SECTION_HEADER*)malloc(sizeof(IMAGE_SECTION_HEADER) * my_data.my_file->NumberOfSections);
		for (int i = 0; i < my_data.my_file->NumberOfSections; i++)
		{
			my_data.my_section[i] = (PIMAGE_SECTION_HEADER)Temp_ptr;
			Temp_ptr = (DWORD*)((char*)Temp_ptr + 0x28);
		}
		return;
	}
	else if(my_data.Stretch_Data!=nullptr)
	{
		DWORD* Temp_ptr = (DWORD*)my_data.Stretch_Data;
		my_data.my_dos = (PIMAGE_DOS_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)my_data.Stretch_Data + my_data.my_dos->e_lfanew);
		Temp_ptr++;
		my_data.my_file = (PIMAGE_FILE_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)Temp_ptr + 0x14);
		my_data.my_optional = (PIMAGE_OPTIONAL_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)my_data.my_optional + my_data.my_file->SizeOfOptionalHeader);
		my_data.my_section = (PIMAGE_SECTION_HEADER*)malloc(sizeof(IMAGE_SECTION_HEADER) * my_data.my_file->NumberOfSections);
		for (int i = 0; i < my_data.my_file->NumberOfSections; i++)
		{
			my_data.my_section[i] = (PIMAGE_SECTION_HEADER)Temp_ptr;
			Temp_ptr = (DWORD*)((char*)Temp_ptr + 0x28);
		}
		return;
	}
	else if (my_data.Shrink_Data != nullptr)
	{
		DWORD* Temp_ptr = (DWORD*)my_data.Shrink_Data;
		my_data.my_dos = (PIMAGE_DOS_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)my_data.Shrink_Data + my_data.my_dos->e_lfanew);
		Temp_ptr++;
		my_data.my_file = (PIMAGE_FILE_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)Temp_ptr + 0x14);
		my_data.my_optional = (PIMAGE_OPTIONAL_HEADER)Temp_ptr;

		Temp_ptr = (DWORD*)((char*)my_data.my_optional + my_data.my_file->SizeOfOptionalHeader);
		my_data.my_section = (PIMAGE_SECTION_HEADER*)malloc(sizeof(IMAGE_SECTION_HEADER) * my_data.my_file->NumberOfSections);
		for (int i = 0; i < my_data.my_file->NumberOfSections; i++)
		{
			my_data.my_section[i] = (PIMAGE_SECTION_HEADER)Temp_ptr;
			Temp_ptr = (DWORD*)((char*)Temp_ptr + 0x28);
		}
		return;
	}

	cout << "分析pe结构失败!" << endl;
	cout << "失败原因,Data类里三个状态的指针皆为空指针!" << endl;
}

//拉伸PE结构   注意看PIMAGE_XXX_HEADER的定义,它们本就是指向结构体的指针
void PE::Stretch_PE(Data& my_data)
{
	unsigned Memory_Size = 0;
	Memory_Size = my_data.my_optional->SizeOfImage;
	my_data.Stretch_Data = (void*)malloc(sizeof(char) * Memory_Size);
	memset(my_data.Stretch_Data, 0, Memory_Size);
	void* temp_before_stretch_data_ptr = my_data.Before_Stretch_Data;
	int size_of_dos = 0x40;
	int size_of_junk = 0x40;
	int size_of_file = 0x18;
	unsigned Size_Of_Optional = my_data.my_file->SizeOfOptionalHeader;
	unsigned Size_Of_Section = 0x28;
	unsigned Size_Of_Header = size_of_dos + size_of_file + size_of_junk + Size_Of_Optional + Size_Of_Section * my_data.my_file->NumberOfSections;//还未对齐
	memcpy_s(my_data.Stretch_Data, Memory_Size, my_data.Before_Stretch_Data, Size_Of_Header);
	void* temp_stretch_data = my_data.Stretch_Data;
	//现在计算head头对齐后的大小
	int Size = Size_Of_Header % my_data.my_optional->SectionAlignment;
	Size_Of_Header = my_data.my_optional->SectionAlignment * Size;


	for (int i = 0; i < my_data.my_file->NumberOfSections; i++)
	{
		temp_stretch_data = (void*)((char*)my_data.Stretch_Data + my_data.my_section[i]->VirtualAddress);
		temp_before_stretch_data_ptr = (void*)((char*)my_data.Before_Stretch_Data + my_data.my_section[i]->PointerToRawData);
		memcpy_s(temp_stretch_data, my_data.my_section[i]->SizeOfRawData, temp_before_stretch_data_ptr, my_data.my_section[i]->SizeOfRawData);
	}
	cout << "拉伸成功" << endl;
}



void PE::Shrink_PE(Data& my_data)
{
	unsigned int Size = 0;
	Size = my_data.my_section[my_data.my_file->NumberOfSections - 1]->PointerToRawData + my_data.my_section[my_data.my_file->NumberOfSections - 1]->SizeOfRawData;
	my_data.Shrink_Data = (void*)malloc(Size);

	//从Stretch_Data缩小

	//复制Heads
	memcpy_s(my_data.Shrink_Data, my_data.my_optional->SizeOfHeaders, my_data.Stretch_Data, my_data.my_optional->SizeOfHeaders);

	//复制节
	void* temp_shrink_data_ptr = my_data.Shrink_Data;
	void* temp_stretch_data_ptr = my_data.Stretch_Data;
	for (int i = 0; i < my_data.my_file->NumberOfSections; i++)
	{
		temp_shrink_data_ptr = (void*)((char*)my_data.Shrink_Data + my_data.my_section[i]->PointerToRawData);
		temp_stretch_data_ptr = (void*)((char*)my_data.Stretch_Data + my_data.my_section[i]->VirtualAddress);
		memcpy_s(temp_shrink_data_ptr, my_data.my_section[i]->SizeOfRawData, temp_stretch_data_ptr, my_data.my_section[i]->SizeOfRawData);
	}
	cout << "缩小成功" << endl;
	return;

}


int main()
{
	char filename[100]= "ceshi.exe";
	PE my_pe;
	Data my_data;
	my_pe.Readfile(filename,my_data);
	my_pe.Analyze_PE(my_data);   //char*& Data, PIMAGE_DOS_HEADER& dos, PIMAGE_FILE_HEADER& file, PIMAGE_OPTIONAL_HEADER32& optional, PIMAGE_SECTION_HEADER*& section
	my_pe.Stretch_PE(my_data);
	my_pe.Shrink_PE(my_data);

	/*char filename2[100] = "666.exe";
	my_pe.New_Section(filename2, my_data);*/

	char filename3[100] = "555.exe";
	my_pe.Expand_Section(my_data,filename3);
	return 0;
	
}

至于刚刚提到的问题,我查看汇编代码发现了些许端倪
 

004C2E4B C7 45 FC FF FF FF FF mov         dword ptr [ebp-4],0FFFFFFFFh  
004C2E52 8D 4D B8             lea         ecx,[Expand_Data]  
004C2E55 E8 08 E4 FF FF       call        Data::~Data (04C1262h)  
004C2E5A 52                   push        edx  
004C2E5B 8B CD                mov         ecx,ebp  
004C2E5D 50                   push        eax  
004C2E5E 8D 15 98 2E 4C 00    lea         edx,ds:[4C2E98h]  
004C2E64 E8 03 E4 FF FF       call        @_RTC_CheckStackVars@8 (04C126Ch)  
004C2E69 58                   pop         eax  
004C2E6A 5A                   pop         edx  
004C2E6B 8B 4D F4             mov         ecx,dword ptr [ebp-0Ch]  
004C2E6E 64 89 0D 00 00 00 00 mov         dword ptr fs:[0],ecx  
004C2E75 59                   pop         ecx  
004C2E76 5F                   pop         edi  
004C2E77 5E                   pop         esi  
004C2E78 5B                   pop         ebx  
004C2E79 8B 4D F0             mov         ecx,dword ptr [ebp-10h]  
004C2E7C 33 CD                xor         ecx,ebp  
004C2E7E E8 21 E3 FF FF       call        @__security_check_cookie@4 (04C11A4h)  
004C2E83 81 C4 3C 01 00 00    add         esp,13Ch  
004C2E89 3B EC                cmp         ebp,esp  
004C2E8B E8 4F E4 FF FF       call        __RTC_CheckEsp (04C12DFh)  
004C2E90 8B E5                mov         esp,ebp  
004C2E92 5D                   pop         ebp  
004C2E93 C2 08 00             ret         8  

这是我传值引用的结果,可以看到只调用了Expand_Data这个类的析构函数,符合常理,但是一旦我将void PE:: Expand_Section(Data& my_data,char* filename)改为void PE:: Expand_Section(Data my_data,char* filename) 我们再反汇编,此时就有问题了!

00AB2E0A C6 45 FC 00          mov         byte ptr [ebp-4],0  
00AB2E0E 8D 4D B8             lea         ecx,[Expand_Data]  
00AB2E11 E8 4C E4 FF FF       call        Data::~Data (0AB1262h)  
00AB2E16 C7 45 FC FF FF FF FF mov         dword ptr [ebp-4],0FFFFFFFFh  
00AB2E1D 8D 4D 08             lea         ecx,[my_data]  
00AB2E20 E8 3D E4 FF FF       call        Data::~Data (0AB1262h)  
00AB2E25 52                   push        edx  
00AB2E26 8B CD                mov         ecx,ebp  
00AB2E28 50                   push        eax  
00AB2E29 8D 15 64 2E AB 00    lea         edx,ds:[0AB2E64h]  
00AB2E2F E8 38 E4 FF FF       call        @_RTC_CheckStackVars@8 (0AB126Ch)  
00AB2E34 58                   pop         eax  
00AB2E35 5A                   pop         edx  
00AB2E36 8B 4D F4             mov         ecx,dword ptr [ebp-0Ch]  
00AB2E39 64 89 0D 00 00 00 00 mov         dword ptr fs:[0],ecx  
00AB2E40 59                   pop         ecx  
00AB2E41 5F                   pop         edi  
00AB2E42 5E                   pop         esi  
00AB2E43 5B                   pop         ebx  
00AB2E44 8B 4D F0             mov         ecx,dword ptr [ebp-10h]  
00AB2E47 33 CD                xor         ecx,ebp  
00AB2E49 E8 56 E3 FF FF       call        @__security_check_cookie@4 (0AB11A4h)  
00AB2E4E 81 C4 3C 01 00 00    add         esp,13Ch  
00AB2E54 3B EC                cmp         ebp,esp  
00AB2E56 E8 84 E4 FF FF       call        __RTC_CheckEsp (0AB12DFh)  
00AB2E5B 8B E5                mov         esp,ebp  
00AB2E5D 5D                   pop         ebp  
00AB2E5E C2 20 00             ret         20h  

可以看到他居然调用了my_data的析构!这也是导致程序崩溃的原因,因为在main函数中,函数结束后,也会调用my_data的析构,等于调用了析构函数两次!

具体原因查了下资料对象作为参数按值传递为什么会调用析构函数?为什么实参中的内容会被修改?_c++ 类作为参数传递 在函数中被修改-CSDN博客

引用大佬的文章

对象作为参数按值传递为什么会调用析构函数?为什么实参中的内容会被修改?

因为对象按值传递时,编译器自动生成的复制构造函数进行了指针的简单拷贝,像指针直接赋值 str=s 一样,而没有拷贝指针指向的内容,这样当你将对象传递给函数时确实会有一个拷贝,但是这个拷贝会有一个指针的拷贝,所以两个对象中的 str 指向的内存一样,在退出函数时,析构销毁了函数中对象中的指针,但不幸的是这样实参对象 str 指向的内容也被销毁。

哎,c++没学好是这样的,但也算收获蛮多 

 

到了这里,关于【逆向】03-20扩大节 c++代码完成 ;类当作函数参数却调用了析构函数疑难分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++|29.纯虚函数/接口(待完成)

    纯虚函数是一种特殊的虚函数。 普通的虚函数允许子类的同名函数对其进行重写,同时普通的虚函数本身是可以单独进行使用的。 而纯虚函数是一个空壳,强制要求所派生的类在继承的过程中必要将该虚函数进行实现。 如上图,纯虚函数只需要在virtual后面添加上=0即可。

    2024年01月16日
    浏览(36)
  • C++ 笔记 20 (STL函数对象)

    1. 函数对象 1.1 函数对象概念 概念: 重载 函数调用操作符 的类,其对象常称为函数对象; 函数对象使用重载的()时,行为类似函数调用,也叫仿函数。 本质: 函数对象(仿函数)是一个类,不是一个函数。 1.2 函数对象的使用 特点: 函数对象在使用时,可以像普通函数

    2024年02月02日
    浏览(43)
  • Nike登录的acw_sc__v2参数逆向详细思路分析(非常简单,建议入手)含AST解混淆代码

    最近周末闲着无事,看了一下Nike的登录,发现连环境都不用补acw_sc__v2这个参数,分享出来给大家趣味性娱乐一下 打开F12抓包看看登录 老样子复制curl给抓到Postman里面去分析一下 具体的参数查找就不演示了(就是简单的删参数看看啥需要啥不需要)。 最后可以发现,cookie只

    2024年02月09日
    浏览(43)
  • 【C++漂流记】函数的高级应用——函数默认参数、占位参数、重载

    函数的高级应用,侧重介绍函数的默认参数、函数的占位参数、函数重载定义解释及使用。 函数默认参数是指在函数声明时为参数提供一个默认值,这样在调用函数时如果没有传入相应的参数,就会使用默认值代替。函数默认参数可以简化函数的调用,使得函数更加灵活。

    2024年02月09日
    浏览(37)
  • C++入门:函数缺省参数与函数重载

    目录 1.函数缺省参数 1.1 缺省参数概念 1.2 缺省参数分类 2.函数重载 2.1 函数重载概念 2.2 C++支持函数重载的原理 缺省参数是 声明或定义函数时 为函数的 参数指定一个缺省值 。在调用该函数时,如果没有指定实 参则采用该形参的缺省值,否则使用指定的实参,有点备胎的意

    2024年02月12日
    浏览(32)
  • C++函数参数匹配规则

    candidate functions:函数名称相同(f1, f2, f3, f4 都是)。 viable functions:参数个数相同(排除f1, f3),且参数可以转换成相同类型(f2, f4都是viable function)。如果不存在viable functions,则编译器报参数不匹配错误(可以通过linting检查)。 最后决定参数类型是否匹配,如果匹配优先调用,不能

    2024年02月12日
    浏览(33)
  • 【C++初阶】C++入门——缺省参数、函数重载

     缺省参数是 声明或定义函数时为函数的参数指定一个缺省值 。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。  上面代码在 fun 函数的形参部分给了缺省值10,这意味着在调用 fun 函数的时候可以传参,也可以不传参,如果传参了那形参

    2024年02月11日
    浏览(37)
  • 【C++】C++ 引用详解 ① ( 变量的本质 - 引入 “ 引用 “ 概念 | 引用语法简介 | 引用做函数参数 | 复杂类型引用做函数参数 )

    \\\" 引用 \\\" 语法 是 C++ 语言中 特有的 , 在 C 语言中是没有 引用 这个概念的 ; 分析 引用 之前 , 先回顾下 变量 : 在 【C 语言】变量本质 ( 变量概念 | 变量本质 - 内存空间别名 | 变量存储位置 - 代码区 | 变量三要素 ) 博客中 , 介绍了变量的本质 : 变量 的本质是 内存空间 的 \\\" 别名

    2024年02月11日
    浏览(49)
  • C++:命名空间,缺省参数,函数重载,引用,内联函数

    个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C++》 本篇博客作为C++知识总结,我们来认识命名空间,缺省参数,函数重载,引用,内联函数。 那么在介绍命名空间时,我们先用C++的方式打印\\\"hello world\\\"。 其中,using namespace std; 就是一种命名空间的使用。 在

    2024年02月11日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包