在解析PE遇到的问题

起因

在解析PE中,使用二级指针了,c语言二级指针的使用 ,在将PE加在到内存拉伸,拷贝section使用出现在了,导致PE加载到内存,保存为PE文件的时候,无法运行.

PE加载到还原为文件

PE加载到内存到还原为文件的过程
c语言二级指针的使用 最下面的一段代码,是有问题的.我们先看看代码.
PIMAGE_SECTION_HEADER temp_section_header = section_header;
for (int i = 0; i < file_header->NumberOfSections; i++)
{
	void* des = (void*)((unsigned long)temp_buffer + temp_section_header->VirtualAddress);   //每次都是获取第一个节的内存地址
	void* src = (void*)((unsigned long)ptemp +(temp_section_header + i)->PointerToRawData);  // 
	memcpy(des, src, temp_section_header->SizeOfRawData);                                     //每次都是一个节的大小
}

在循环内的3行代码,有两个代码是问题的(第一行和第三行).

正确的代码

PIMAGE_SECTION_HEADER temp_section_header = section_header;
for (int i = 0; i < file_header->NumberOfSections; i++)
{
	PIMAGE_SECTION_HEADER psection = temp_section_header + i;
	void* des = (void*)((unsigned long)temp_buffer + psection->VirtualAddress);
	void* src = (void*)((unsigned long)ptemp + psection->PointerToRawData);  //temp_section_header + 1,移动多少呢?
	memcpy(des, src, psection->SizeOfRawData);
}

拉伸

拉伸:读取section(节)在文件中的PointerToRawData(在文件中的偏移量),大小为SizeOfRawData(文件中对齐的长度)

//将pe文件(在内存中,还是文件布局)转换为pe在内存布局
unsigned long buffer_to_image(char** file_buffer, char** image_buffer)
{
	PIMAGE_DOS_HEADER dos_header = NULL;
	PIMAGE_NT_HEADERS nt_header = NULL;
	PIMAGE_FILE_HEADER file_header = NULL;
	PIMAGE_OPTIONAL_HEADER optional_header = NULL;
	PIMAGE_SECTION_HEADER section_header = NULL;

	char* ptemp = *file_buffer;

	void* temp_buffer = NULL;
	if (file_buffer == NULL)
	{
		printf("file_buff is null\n");
		return 0;
	}

	if (*(short*)ptemp != IMAGE_DOS_SIGNATURE)
	{
		printf("%08x\n", *(short*)ptemp);
		//校验是否为dos头 pe开头为mz
		return 0;
	}
	dos_header = (PIMAGE_DOS_HEADER)ptemp;

	if (*(short*)((unsigned long)ptemp + dos_header->e_lfanew) != IMAGE_NT_SIGNATURE)
	{
		//校验nt头是否有pe标志 PE
		return 0;
	}
	nt_header = (PIMAGE_NT_HEADERS)((unsigned long)ptemp + dos_header->e_lfanew);
	file_header = (PIMAGE_FILE_HEADER)((unsigned long)nt_header + 4);
	optional_header = (PIMAGE_OPTIONAL_HEADER)((unsigned long)file_header + IMAGE_SIZEOF_FILE_HEADER);

	section_header = (PIMAGE_SECTION_HEADER)((unsigned long)optional_header + file_header->SizeOfOptionalHeader);

	//分配空间
	temp_buffer = calloc(1, optional_header->SizeOfImage);
	if (!temp_buffer)
	{
		temp_buffer = NULL;
		return 0;
	}

	//从dos头开始拷贝,拷贝首部+块表的大小,到内存中
	memcpy(temp_buffer, dos_header, optional_header->SizeOfHeaders);  //SizeOfHeaders为首部及块表(首部+块表)的大小


	PIMAGE_SECTION_HEADER temp_section_header = section_header;
	for (int i = 0; i < file_header->NumberOfSections; i++)
	{
		PIMAGE_SECTION_HEADER psection = temp_section_header + i;
		void* des = (void*)((unsigned long)temp_buffer + psection->VirtualAddress);
		void* src = (void*)((unsigned long)ptemp + psection->PointerToRawData);  
		memcpy(des, src, psection->SizeOfRawData);
	}

	*image_buffer = temp_buffer;
	return optional_header->SizeOfImage;		   //SizeOfImage在内存中整个PE映像的大小
}


还原


//从内存还原为文件
int recovery_file(void** image_buffer, char* file, int size)
{
	PIMAGE_DOS_HEADER dos_header = NULL;
	PIMAGE_NT_HEADERS nt_header = NULL;
	PIMAGE_FILE_HEADER file_header = NULL;
	PIMAGE_OPTIONAL_HEADER optional_header = NULL;
	PIMAGE_SECTION_HEADER section_header = NULL;

	char* ptemp = *image_buffer;
	dos_header = (PIMAGE_DOS_HEADER)ptemp;
	if (*(short*)((unsigned long)ptemp + dos_header->e_lfanew) != IMAGE_NT_SIGNATURE)
	{
		//校验nt头是否有pe标志 PE
		return 0;
	}

	nt_header = (PIMAGE_NT_HEADERS)((unsigned long)ptemp + dos_header->e_lfanew);
	file_header = (PIMAGE_FILE_HEADER)((unsigned long)nt_header + 4);
	optional_header = (PIMAGE_OPTIONAL_HEADER)((unsigned long)file_header + IMAGE_SIZEOF_FILE_HEADER);
	section_header = (PIMAGE_SECTION_HEADER)((unsigned long)optional_header + file_header->SizeOfOptionalHeader);
	char* file_buffer = calloc(1, size);
	memcpy(file_buffer, dos_header, optional_header->SizeOfHeaders);

	PIMAGE_SECTION_HEADER temp_section_header = section_header;
	for (int i = 0; i < file_header->NumberOfSections; i++)
	{
		PIMAGE_SECTION_HEADER psection = temp_section_header + i;
		void* des = (void*)((unsigned long)file_buffer + psection->PointerToRawData);
		void* src = (void*)((unsigned long)ptemp + psection->VirtualAddress);  
		memcpy(des, src, psection->SizeOfRawData);
	}

	FILE* fp = fopen(file, "wb+");
	if (fp != NULL)
	{
		fwrite((void*)file_buffer, size, 1, fp);
	}
	fclose(fp);
}


秋风 2019-07-21