pe文件结构笔记
可执行文件(exe)指的是操作系统可以加载执行的文件,即程序在什么平台上运行就要遵守什么平台的文件格式。
Windows平台:PE(Portable Executable)文件结构
Linux平台:ELF( Executable and Linking Format)文件结构
如何识别pe文件(pe指纹)
1观察前两个字节,是否为MZ
2查找地址0000003Ch的值,这个值是多少就查找相应的内存地址,如当前E8就查找000000E8h
3观察从e8开始后两个字节,是否为PE
满足以上条件几乎可以断定这就是一个pe文件、
不要光看文件后缀名判断!
应当根据pe文件的规范和定义来判断
那么其他字节有没有意义呢,自然是有的
先·从整体来看看pe文件
部分结构体所占字节,下面依次介绍这些结构体
dos stub(dos块)由链接器决定,可更改,大小不确定
但是dos mz文件头的最后一个成员(占4字节)指向pe文件头开始的位置,由此可判断出dos块的大小。
pe文件头
三个成员分别为pe文件头标志(无意义字符串显示PE就是他,四字节)标准pe头(20字节),可选pe头(32位224字节和64位不一样)。
//可选PE头
struct _IMAGE_OPTIONAL_HEADER{
0x00 WORD Magic; //※幻数(魔数),0x0107:ROM image,0x010B:32位PE,0X020B:64位PE
//0x02 BYTE MajorLinkerVersion; //连接器主版本号
//0x03 BYTE MinorLinkerVersion; //连接器副版本号
0x04 DWORD SizeOfCode; //所有代码段的总和大小,注意:必须是FileAlignment的整数倍,存在但没用
0x08 DWORD SizeOfInitializedData; //已经初始化数据的大小,注意:必须是FileAlignment的整数倍,存在但没用
0x0c DWORD SizeOfUninitializedData; //未经初始化数据的大小,注意:必须是FileAlignment的整数倍,存在但没用
0x10 DWORD AddressOfEntryPoint; //※程序入口地址OEP,这是一个RVA(Relative Virtual Address),通常会落在.textsection,此字段对于DLLs/EXEs都适用。
0x14 DWORD BaseOfCode; //代码段起始地址(代码基址),(代码的开始和程序无必然联系)
0x18 DWORD BaseOfData; //数据段起始地址(数据基址)
0x1c DWORD ImageBase; //※内存镜像基址(默认装入起始地址),默认为4000H
0x20 DWORD SectionAlignment; //※内存对齐:一旦映像到内存中,每一个section保证从一个「此值之倍数」的虚拟地址开始
0x24 DWORD FileAlignment; //※文件对齐:最初是200H,现在是1000H
//0x28 WORD MajorOperatingSystemVersion; //所需操作系统主版本号
//0x2a WORD MinorOperatingSystemVersion; //所需操作系统副版本号
//0x2c WORD MajorImageVersion; //自定义主版本号,使用连接器的参数设置,eg:LINK /VERSION:2.0 myobj.obj
//0x2e WORD MinorImageVersion; //自定义副版本号,使用连接器的参数设置
//0x30 WORD MajorSubsystemVersion; //所需子系统主版本号,典型数值4.0(Windows 4.0/即Windows 95)
//0x32 WORD MinorSubsystemVersion; //所需子系统副版本号
//0x34 DWORD Win32VersionValue; //总是0
0x38 DWORD SizeOfImage; //※PE文件在内存中映像总大小,sizeof(ImageBuffer),SectionAlignment的倍数
0x3c DWORD SizeOfHeaders; //※DOS头(64B)+PE标记(4B)+标准PE头(20B)+可选PE头+节表的总大小,按照文件对齐(FileAlignment的倍数)
0x40 DWORD CheckSum; //PE文件CRC校验和,判断文件是否被修改
//0x44 WORD Subsystem; //用户界面使用的子系统类型
//0x46 WORD DllCharacteristics; //总是0
0x48 DWORD SizeOfStackReserve; //默认线程初始化栈的保留大小
0x4c DWORD SizeOfStackCommit; //初始化时实际提交的线程栈大小
0x50 DWORD SizeOfHeapReserve; //默认保留给初始化的process heap的虚拟内存大小
0x54 DWORD SizeOfHeapCommit; //初始化时实际提交的process heap大小
//0x58 DWORD LoaderFlags; //总是0
0x5c DWORD NumberOfRvaAndSizes; //目录项数目:总为0X00000010H(16)
0x60 _IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];//#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
};