PE头结构说明及C语言解析
文章目录
0.说明
看滴水初期视频PE部分的笔记
1.PE的整个结构
2.PE结构详解
我这里只没有写数据项,因为还不怎么会0.0
有些数据也没写,因为现阶段还没用
DOS头
WORD e_magic * | “MZ标记” 用于判断是否为可执行文件. |
---|---|
DWORD e_lfanew; * | PE头相对于文件的偏移,用于定位PE文件 |
NT头
PE标签(PE_NT_SIGNATURE)
DWORD Signature; * | “PE”标记,也用于判断是否为PE文件 |
---|
PE文件头(PE_FIEL_HEADER)
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)
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;* | 目录项数目 |
节表头
1、Name | 8个字节 一般情况下是以"\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
直接贴源码
编译环境: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;
}
欢迎大家留言交友^ & ^