PE文件复看:打印PE头信息

PE文件解析打印头部信息

  • 1.把文件读取到堆空间
  • 2.调用函数
  • 3.代码运行结果
  • 4.代码规范

1.把文件读取到堆空间

以后对PE文件进行频繁的操作总是绕不开第一步,就是把PE文件的信息读取到自己申请的堆空间中,所以先实现这个函数,以便于以后频繁使用。
函数

  • ReadPEfile_TO_FileBuffer

功能说明

  • 把PE文件以二进制的读方式读取到FileBuffer堆空间
DWORD ReadPEfile_TO_FileBuffer(IN char* filepath, OUT void** FileBuffer)
{
     
	//打开文件,读取PE文件
	FILE* fileAddress = fopen(filepath, "rb");
	if (!fileAddress)
	{
     
		printf("打开文件失败!!");
		return 0;
	}
	//计算PE文件大小
	fseek(fileAddress, 0, SEEK_END);
	DWORD Filesize = ftell(fileAddress);
	//将指针移动到开头,为了下面读取文件
	//或者使用rewind函数
	fseek(fileAddress, 0, SEEK_SET);
	//申请堆空间
	void* Temp_FileBuffer = malloc(Filesize);
	if (!Temp_FileBuffer)
	{
     
		printf("分配Temp_FileBuffer空间失败!!");
		fclose(fileAddress);
		return 0;
		
	}
	memset(Temp_FileBuffer, 0, Filesize);
	//将文件内容读取到堆空间
	size_t Terms = fread(Temp_FileBuffer, Filesize, 1, fileAddress);
	if (!Terms)
	{
     
		printf("读入FileBuffer失败!!!");
		free(Temp_FileBuffer);
		fclose(fileAddress);
		return 0;
	}
	//关闭文件 ,将Temp_FileBuffer的值传给FileBuffer
	fclose(fileAddress);
	*FileBuffer = Temp_FileBuffer;
	return Filesize;
}

2.调用函数

上面已经实现了一个将PE文件读取到FileBuffer堆空间的操作,那么下面就是要调用这个函数,然后对读取到堆空间中的数据进行打印,要了解PE结构才可以实现。

void Test_PrintHeaderInformation()
{
     
	void* FileBuffer = NULL;
	//读取文件到FileBuffer
	//&FileBuffer 记得释放堆空间,指向堆空间的就是FileBuffer
	//FILEPATHIN就是个文件路径,是个宏定义的一个字符串,你也可以用指针存储
	DWORD FileSize = ReadPEfile_TO_FileBuffer(FILEPATH_IN, &FileBuffer);
	printf("读取成功,此空间大小为%x,下面开始查看此空间信息!\n", FileSize);
	printf("\n");
	//罗列出需要用到的结构体指针
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	PIMAGE_FILE_HEADER pPEHeader = NULL;
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	pDosHeader = (PIMAGE_DOS_HEADER)FileBuffer;
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)FileBuffer + pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + 20);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	//解析DOS头信息
	if (*((WORD*)pDosHeader) != IMAGE_DOS_SIGNATURE)
	{
     
		printf("这不是exe文件!!!!!!!");
		free(FileBuffer);
		return;
	}
	printf("********************DOS头解析********************\n");
	printf("e_magic的值为:%x\n", pDosHeader->e_magic);
	printf("e_lfanew的值为:%x\n", pDosHeader->e_lfanew);
	printf("\n");
	//解析NT头信息
	if (*(DWORD*)pNTHeader != IMAGE_NT_SIGNATURE)
	{
     
		printf("这不是PE标志!!!!!!!");
		free(FileBuffer);
		return;
	}
	printf("********************NT头解析*********************\n");
	printf("PE标志:%x\n", pNTHeader->Signature);
	printf("\n");
	//标准PE头解析
	printf("*******************标准PE头解析*********************\n");
	printf("PE_Machine:%x\n", pPEHeader->Machine);
	printf("PE节数量:%x\n", pPEHeader->NumberOfSections);
	printf("PE_TimeDataStamp:%x\n", pPEHeader->TimeDateStamp);
	printf("可选PE头大小:%x\n", pPEHeader->SizeOfOptionalHeader);
	printf("Characteristics:%x*\n", pPEHeader->Characteristics);
	printf("\n");
	//可选PE头解析
	printf("===================可选PE头解析===================\n");
	printf("Magic:%x\n", pOptionHeader->Magic);
	printf("SizeOfCode:%x\n", pOptionHeader->SizeOfCode);
	printf("SizeOfInitializedData:%x\n", pOptionHeader->SizeOfInitializedData);
	printf("SizeOfUnitializedData:%x\n", pOptionHeader->SizeOfUninitializedData);
	printf("AddressOfEntryPoint:%x\n", pOptionHeader->AddressOfEntryPoint);
	printf("BaseOfCode :%x\n", pOptionHeader->BaseOfCode);
	printf("BaseOfData:%x\n", pOptionHeader->BaseOfData);
	printf("ImageBase:%x\n", pOptionHeader->ImageBase);
	printf("SectionAlignment:%x\n", pOptionHeader->SectionAlignment);
	printf("FileAlignment:%x\n", pOptionHeader->FileAlignment);
	printf("SizeOfImage:%x\n", pOptionHeader->SizeOfImage);
	printf("SizeOfHeaders:%x\n", pOptionHeader->SizeOfHeaders);
	printf("SizeOfStackReserve:%x\n", pOptionHeader->SizeOfStackReserve);
	printf("SizeOfStackCommit:%x\n", pOptionHeader->SizeOfStackCommit);
	printf("SizeOfHeapReserve:%x\n", pOptionHeader->SizeOfHeapReserve);
	printf("SizeOfHeapCommit:%x\n", pOptionHeader->SizeOfHeapCommit);
	printf("\n");
	//节表解析,循环打印节表
	PIMAGE_SECTION_HEADER Temp_pSectionHeader = pSectionHeader;
	for (DWORD i = 1; i <= pPEHeader->NumberOfSections; i++, Temp_pSectionHeader++)
	{
     
		printf("**************************第%d个节表**********************\n", i);
		printf("Section_Name:");
		for (int j = 0; j < 8; j++)
		{
     
			printf("%c", Temp_pSectionHeader->Name[j]);
		}
		printf("\n");
		printf("misc:%x\n", Temp_pSectionHeader->Misc);
		printf("VirtualAddress:%x\n", Temp_pSectionHeader->VirtualAddress);
		printf("SizeOfRawData:%x\n", Temp_pSectionHeader->SizeOfRawData);
		printf("PointerToRawData:%x\n", Temp_pSectionHeader->PointerToRawData);
		printf("Characteristics:%x\n", Temp_pSectionHeader->Characteristics);
	}
	printf("\n");
	//记得释放堆空间
	free(FileBuffer);
}

值得注意的是在打印节表的时候最好不要用%s格式符printf("%s", Temp_pSectionHeader->Name);因为节表结构中的第一个成员不遵守以0结尾的特性,如果运气不好,你的节的名字正好占8个字节,那么恭喜你,将会读取越界,直到为0为止

3.代码运行结果

PE文件复看:打印PE头信息_第1张图片

4.代码规范

main函数里面最好什么都别写,将函数的实现放在单独的一个C文件中,将函数的声明放在H文件中,就拿上面写的代码为例,第一个函数我要频繁调用,所以我可以将代码的实现放在一个C文件中,将函数的声明放在另一个文件中
DWORD ReadPEfile_TO_FileBuffer(IN char* filepath, OUT void** FileBuffer)
同理,我测试这些主要频繁用到的函数也单独建一个C文件和一个H文件
PE文件复看:打印PE头信息_第2张图片
如下,调用Test_PrintHeaderInformation()

int main(int argc,char* argv[])
{
     
	Test_PrintHeaderInformation();
	return 0;
}

你可能感兴趣的:(PE文件,指针,c语言)