PE头结构说明及C语言解析

PE头结构说明及C语言解析

0.说明

看滴水初期视频PE部分的笔记

1.PE的整个结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bwi14YUk-1589188277430)(D:\user\Desktop\学习笔记\2020.5.11_PE头结构说明及C语言解析\image-20200511163113125.png)]

2.PE结构详解

我这里只没有写数据项,因为还不怎么会0.0

有些数据也没写,因为现阶段还没用

DOS头

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dNzagKsv-1589188277434)(E:\Typora\image\image-20200511170612245.png)]

WORD e_magic *“MZ标记” 用于判断是否为可执行文件.
DWORD e_lfanew; *PE头相对于文件的偏移,用于定位PE文件

NT头

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aQKaU3Px-1589188277435)(E:\Typora\image\image-20200511170630256.png)]

PE标签(PE_NT_SIGNATURE)
DWORD Signature; *“PE”标记,也用于判断是否为PE文件
PE文件头(PE_FIEL_HEADER)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hSr0SB4K-1589188277437)(E:\Typora\image\image-20200511170654163.png)]

WORD Machine; *程序运行的CPU型号:0x0 任何处理器/0x14C 386及后续处理器
WORD NumberOfSections; *文件中存在的节的总数,如果要新增节或者合并节 就要修改这个值.
DWORD TimeDateStamp; *时间戳:文件的创建时间(和操作系统的创建时间无关),编译器填写的.
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader; *可选PE头的大小,32位PE文件默认E0h 64位PE文件默认为F0h 大小可以自定义.
WORD Characteristics; *每个位有不同的含义,可执行文件值为10F 即0 1 2 3 8位置1
PE可选头(PE_OPTIONAL_HEADER)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1TzP5JZI-1589188277439)(E:\Typora\image\image-20200511170712849.png)]

WORD Magic; *说明文件类型:10B 32位下的PE文件 20B 64位下的PE文件
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;*所有代码节的和,必须是FileAlignment的整数倍 编译器填的 没用
DWORD SizeOfInitializedData;*已初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用
DWORD SizeOfUninitializedData;*未初始化数据大小的和,必须是FileAlignment的整数倍 编译器填的 没用
DWORD AddressOfEntryPoint;*程序入口
DWORD BaseOfCode;*代码开始的基址,编译器填的 没用
DWORD BaseOfData;*数据开始的基址,编译器填的 没用
DWORD ImageBase;*内存镜像基址
DWORD SectionAlignment;*内存对齐
DWORD FileAlignment;*文件对齐
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;*内存中整个PE文件的映射的尺寸,可以比实际的值大,但必须是SectionAlignment的整数倍
DWORD SizeOfHeaders;*所有头+节表按照文件对齐后的大小,否则加载会出错
DWORD CheckSum;*校验和,一些系统文件有要求.用来判断文件是否被修改.
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;*初始化时保留的堆栈大小
DWORD SizeOfStackCommit;*初始化时实际提交的大小
DWORD SizeOfHeapReserve;*初始化时保留的堆大小
DWORD SizeOfHeapCommit;*初始化时实践提交的大小
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;*目录项数目

节表头

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xrTy05uT-1589188277440)(E:\Typora\image\image-20200511170728735.png)]

1、Name8个字节 一般情况下是以"\0"结尾的ASCII吗字符串来标识的名称,内容可以自定义.
注意:该名称并不遵守必须以"\0"结尾的规律,如果不是以"\0"结尾,系统会截取8个字节的长度进行处理.
2、Misc 双字 是该节在没有对齐前的真实尺寸,该值可以不准确。
3、VirtualAddress 节区在内存中的偏移地址。加上ImageBase才是在内存中的真正地址.
4、SizeOfRawData 节在文件中对齐后的尺寸.
5、PointerToRawData 节区在文件中的偏移.
6、PointerToRelocations 在obj文件中使用 对exe无意义
7、PointerToLinenumbers 行号表的位置 调试的时候使用
8、NumberOfRelocations 在obj文件中使用 对exe无意义
9、NumberOfLinenumbers 行号表中行号的数量 调试的时候使用
10、Characteristics 节的属性

3.C语言实现解析PE头文件

也没有解析数据项,因为不会0.0

可能不是很好看,但是功能算是实现了0.0

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GehsQWJX-1589188277441)(E:\Typora\image\image-20200511170908412.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QOj6QRkU-1589188277442)(E:\Typora\image\image-20200511170920314.png)]

直接贴源码
编译环境:vc++6.0

#include<stdio.h>
#include<string.h>
#include<windows.h>
	
char FileName[100]={0};



	
void PrintNTHeaders();
LPVOID ReadPEFile();	
	
int main()
{	
	printf("Please input:   (for example:  D:/user/Desktop/PE文件对齐、内存对齐/解析pe头文件/实验.exe   )\n");
	gets(FileName);
	
	PrintNTHeaders();

	puts(FileName);
	return 0;
}	
	
	
void PrintNTHeaders()
{	
	LPVOID pFileBuffer = NULL;//文件缓冲区
	PIMAGE_DOS_HEADER pDosHeader = NULL;//DOS头
	PIMAGE_NT_HEADERS32 pNTHeader = NULL;//NT头
	PIMAGE_FILE_HEADER pFileHeader =NULL;//文件头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;//可选头
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;//节表头

	size_t i;//循环打印 节区头
	size_t j;
	
	//读取文件进缓冲区
	pFileBuffer = ReadPEFile();
	if(!pFileBuffer)
	{
		printf("file read failure!\n");
		return ;
	}
	
	//判断是否有效的MZ标志
	if(*(PWORD)pFileBuffer != IMAGE_DOS_SIGNATURE)
	{
		printf("not a void 'MZ' flag!\n");
		free(pFileBuffer);
		return ;
	}

	//打印DOC头
	pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer;
	
	printf("\n*****************DOC Header*******************\n");
	printf("'MZ' Flag: %x\n",pDosHeader->e_magic);
	printf("PE Offset: %x\n",pDosHeader->e_lfanew);
	
	//判断是否有效的PE标志
	if( *((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE )
	{	
		printf("not a void PE flag\n");
		free(pFileBuffer);
		return ;
	}

//打印NT头
	pNTHeader = (PIMAGE_NT_HEADERS32)((DWORD)pFileBuffer + pDosHeader->e_lfanew );//DWORD强转 很重要
	
	printf("\n**********************************************************************\n");
	printf("\n********************************NT Header*****************************\n");
	printf("NT Flag: %x\n",pNTHeader->Signature);
	
	//打印PE文件头
	pFileHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4);//DWORD强转 很重要
	
	printf("*************************File Header****************\n");
	printf("Machine: %x\n",pFileHeader->Machine );
	printf("NumberOfSections: %x\n",pFileHeader->NumberOfSections );
	printf("TimeDateStamp: %x\n",pFileHeader->TimeDateStamp );
	printf("PointerToSymbolTable: %x\n",pFileHeader->PointerToSymbolTable );
	printf("NumberOfSymbols: %x\n",pFileHeader->NumberOfSymbols );
	printf("SizeOfOptionalHeader: %x\n",pFileHeader->SizeOfOptionalHeader );
	printf("Characteristics: %x\n",pFileHeader->Characteristics );

	//打印PE 可选头
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+IMAGE_SIZEOF_FILE_HEADER);//DWORD强转 很重要
	
	printf("***********************Optional Header******************\n");
	printf("Magic: %x\n",pOptionHeader->Magic);
	printf("MajorLinkerVersion: %x\n",pOptionHeader->MajorLinkerVersion);
	printf("MinorLinkerVersion: %x\n",pOptionHeader->MinorLinkerVersion);
	printf("SizeOfCode: %x\n",pOptionHeader->SizeOfCode);
	printf("SizeOfInitializedData: %x\n",pOptionHeader->SizeOfInitializedData);
	printf("SizeOfUninitializedData: %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("MajorOperatingSystemVersion: %x\n",pOptionHeader->MajorOperatingSystemVersion);
	printf("MinorOperatingSystemVersion: %x\n",pOptionHeader->MinorOperatingSystemVersion);
	printf("MajorImageVersion: %x\n",pOptionHeader->MajorImageVersion);
	printf("MinorImageVersion: %x\n",pOptionHeader->MinorImageVersion);
	printf("MajorSubsystemVersion: %x\n",pOptionHeader->MajorSubsystemVersion);
	printf("MinorSubsystemVersion: %x\n",pOptionHeader->MinorSubsystemVersion);
	printf("Win32VersionValue: %x\n",pOptionHeader->Win32VersionValue);
	printf("SizeOfImage: %x\n",pOptionHeader->SizeOfImage);
	printf("SizeOfHeaders: %x\n",pOptionHeader->SizeOfHeaders);
	printf("CheckSum: %x\n",pOptionHeader->CheckSum);
	printf("Subsystem: %x\n",pOptionHeader->Subsystem);
	printf("DllCharacteristics: %x\n",pOptionHeader->DllCharacteristics);
	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("LoaderFlags: %x\n",pOptionHeader->LoaderFlags);
	printf("NumberOfRvaAndSizes: %x\n",pOptionHeader->NumberOfRvaAndSizes);

	//打印节表
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pFileHeader->SizeOfOptionalHeader );//DWORD强转 很重要

	printf("\n***************************************************************\n\n");
	printf("***********************Section Header****************************\n");
	
	for(i = pFileHeader->NumberOfSections ; i>0 ; i--)
	{
		printf("Name: ");
		for(j=0 ; j<IMAGE_SIZEOF_SHORT_NAME ; j++)	
			printf("%c",pSectionHeader->Name[j]);
		printf("\n");

	//	printf("VirtualSize(Misc): %x\n",pSectionHeader->Misc.VirtualSize  );
		printf("VirtualAddress: %x\n",pSectionHeader->VirtualAddress );
		printf("SizeOfRawData: %x\n",pSectionHeader->SizeOfRawData);
		printf("PointerToRawData: %x\n",pSectionHeader->PointerToRawData);
		printf("PointerToRelocations: %x\n",pSectionHeader->PointerToRelocations);
		printf("PointerToLinenumbers: %x\n",pSectionHeader->PointerToLinenumbers);
		printf("NumberOfRelocations: %x\n",pSectionHeader->NumberOfRelocations);
		printf("NumberOfLinenumbers: %x\n",pSectionHeader->NumberOfLinenumbers);
		printf("Characteristics: %x\n",pSectionHeader->Characteristics);

		pSectionHeader = (PIMAGE_SECTION_HEADER)( (DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER );
		printf("\n");
	}
	
	



	
	//释放内存
	free(pFileBuffer);
}	


LPVOID ReadPEFile()
{
	FILE* pFile = NULL;
	DWORD FileSize = 0;
	LPVOID pFileBuffer = 0;
	size_t flag = 0;

//	size_t i ;
	
	//打开文件
	pFile = fopen(FileName , "rb");
	if(!pFile)
	{
		printf("open file failure!\n");
		return NULL;
	}
	
	//读取文件大小
	fseek(pFile , 0, SEEK_END);
	FileSize = ftell(pFile);
	
	fseek(pFile , 0 , SEEK_SET);

	//分配缓冲区
	pFileBuffer = malloc(FileSize);
	if(!pFileBuffer)
	{
		printf("allocation space failure!\n");
		fclose(pFile);
		return NULL;
	}
	
	//将文件数据读取到缓冲区
	flag = fread(pFileBuffer , FileSize , 1 , pFile);
	if(!flag)
	{
		printf("read data failure!\n");
		fclose(pFile);
		free(pFile);
		return NULL;
	}
/*输出16进制数据
	for(i=0 ; i<FileSize;i++)
	{
		printf("%x",*((byte*)pFileBuffer+i));
	}
*/
	//关闭文件
	fclose(pFile);

	//返回指针 指向文件数据
	return pFileBuffer;
}


欢迎大家留言交友^ & ^

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值