![PE文件结构](https://img-blog.csdnimg.cn/4fcf86822210401bbb62f5b06d026d93.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAYOa1geW5tOOBpQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
file header Characteristics
option PE code
-
pe文档
//可选PE头 IMAGE_OPTIONAL_HEADER32 STRUCT{ 0x00 WORD Magic; // 标志字, ROM 映像(0107h),普通可执行文件(010Bh) 010B 0x02 BYTE MajorLinkerVersion; // 链接程序的主版本号 05 0x03 BYTE MinorLinkerVersion; // 链接程序的次版本号 0C 0x04 DWORD SizeOfCode; // 所有含代码的节的总大小 0000200 0x08 DWORD SizeOfInitializedData; // 所有含已初始化数据的节的总大小 00000400 0x0c DWORD SizeOfUninitializedData; // 所有含未初始化数据的节的大小 00000000 0x10 DWORD AddressOfEntryPoint; // 程序执行入口RVA 00001000 0x14 DWORD BaseOfCode; // 代码的区块的起始RVA (代码段基址) 00001000 0x18 DWORD BaseOfData; // 数据的区块的起始RVA (数据段基址) 00002000 0x1c DWORD ImageBase; // 程序的首选装载地址 00400000 0x20 DWORD SectionAlignment; // 内存中的区块的对齐大小 00001000 0x24 DWORD FileAlignment; // 文件中的区块的对齐大小 00000200 0x28 WORD MajorOperatingSystemVersion; // 要求操作系统最低版本号的主版本号 0004 0x2a WORD MinorOperatingSystemVersion; // 要求操作系统最低版本号的副版本号 0000 0x2c WORD MajorImageVersion; // 可运行于操作系统的主版本号 0004 0x2e WORD MinorImageVersion; // 可运行于操作系统的次版本号 0000 0x30 WORD MajorSubsystemVersion; // 要求最低子系统版本的主版本号 0004 0x32 WORD MinorSubsystemVersion; // 要求最低子系统版本的次版本号 0000 0x34 DWORD Win32VersionValue; // 莫须有字段,不被病毒利用的话一般为0 00000000 0x38 DWORD SizeOfImage; // 映像装入内存后的总尺寸 00003038 0x3c DWORD SizeOfHeaders; // 所有头 + 区块表的尺寸大小 00000200 0x40 DWORD CheckSum; // 映像的校检和 000020A7 0x44 WORD Subsystem; // 可执行文件期望的子系统 0002 0x46 WORD DllCharacteristics; // DllMain()函数何时被调用,默认为 0 0000 0x48 DWORD SizeOfStackReserve; // 初始化时保留堆栈虚拟内存大小 00100000 0x4c DWORD SizeOfStackCommit; // 初始化时实际提交的堆栈大小 00001000 0x50 DWORD SizeOfHeapReserve; // 初始化时保留的堆大小 00100000 0x54 DWORD SizeOfHeapCommit; // 初始化时提交的堆大小 00001000 0x58 DWORD LoaderFlags; // 与调试有关,默认为 0 00000000 0x5c DWORD NumberOfRvaAndSizes; // 下边数据目录的项数,这个字段自Windows NT 发布以来一直是16 00000010 0x60 IMAGE_DATA_DIRECTORY DataDirectory[16]; // 数据目录表(数目固定为16,很重要!!!) }
-
统计出来的PE头大小为:
1x2=2 2x9=18 19x4=76 2+18+76=96 --> 96byte
总大小:96字节 == 60h字节
-
解释
MajorOperatingSystemVersion : 操作系统主版本号,这里是 0 x 04 \color{red}{0x04} 0x04
SubSystem:常见的子系统,是一个枚举值
SizeOfStackReserve:要保留的堆栈的大小。只有SizeOfStackCommit被提交,其余部分一次提供一页,直到达到保留大小-
重要字段
M a g i c \color{blue}{Magic} Magic: 表示其是32位PE文件,还是64位PE文件。 0 x 010 B \color{red}{0x010B} 0x010B是32位PE文件,0x020B是64位PE文件;如果为0107H,则表示文件为ROM映像。
S i z e O f c o d e \color{blue}{SizeOfcode} SizeOfcode:存放总代码(代码段)大小,按照FileAlignment对齐后的大小 0 x 200 \color{red}{0x200} 0x200
S i z e O f I n i t i a l i z e d D a t a \color{blue}{SizeOfInitializedData} SizeOfInitializedData:已初始化的数据大小,按照FileAlignment对齐 0 x 0400 \color{red}{0x0400} 0x0400
S i z e O f U n i n i t i a l i z e d D a t a \color{blue}{SizeOfUninitializedData} SizeOfUninitializedData:未初始化的数据大小,按照FileAlignment对齐 0 x 0000 \color{red}{0x0000} 0x0000
A d d r e s s O f E n t r y P o i n t \color{blue}{AddressOfEntryPoint} AddressOfEntryPoint:程序入口地址–也叫OEP
- 也是一个偏移地址,是从 程 序 被 加 载 到 内 存 后 在 内 存 中 的 首 地 址 \color{orange}{程序被加载到内存后在内存中的首地址} 程序被加载到内存后在内存中的首地址的偏移地址。
- 也就是说PE文件的起始地址,就等于程序加载进入内存后,把程序在内存中的首地址加上OEP的地址就是程序加载进去后跑的第一行代码的地址。
- 也就是 OEP+ImageBase 的地址,就是一个程序真正的入口地址 0 x 1000 \color{red}{0x1000} 0x1000
I m a g e B a s e \color{blue}{ImageBase} ImageBase1:内存镜像基址,也就是 程 序 加 载 到 内 存 后 在 内 存 中 的 首 地 址 \color{orange}{程序加载到内存后在内存中的首地址} 程序加载到内存后在内存中的首地址 0 x 400000 \color{red}{0x400000} 0x400000
S e c t i o n A l i g n m e n t \color{blue}{SectionAlignment} SectionAlignment:内存对齐大小 0 x 1000 \color{red}{0x1000} 0x1000
F i l e A l i g n m e n t \color{blue}{FileAlignment} FileAlignment:表示文件(硬盘)中的对齐值 0 x 200 \color{red}{0x200} 0x200
S i z e O f I m a g e \color{blue}{SizeOfImage} SizeOfImage:加载到内存中所占的大小(PE加载器根据此处值决定申请连续内存空间大小) 0 x 3038 \color{red}{0x3038} 0x3038
S i z e O f H e a d e r s \color{blue}{SizeOfHeaders} SizeOfHeaders:DOS头+NT头+标准PE头(文件头)+可选PE头+区快表,按照FileAlignment对齐后的大小 0 x 200 \color{red}{0x200} 0x200
I M A G E _ D A T A _ D I R E C T O R Y D a t a D i r e c t o r y \color{blue}{IMAGE\_DATA\_DIRECTORY DataDirectory} IMAGE_DATA_DIRECTORYDataDirectory:
struct _IMAGE_DATA_DIRECTORY{ DWORD VirtualAddress; // 指向某个数据的相对虚拟地址 RAV 偏移0x00** DWORD Size; // 某个数据块的大小 偏移0x04** }; //占用16*8 = 128Byte = 80H = E0H(可选PE头默认大小) - 60H(前面所有成员固定占用大小)
VirtualAddress对应关系
例: #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory 输出表
自认为文件头(file header)和DOS头已经掌握差不多了
-
FileBuffer是磁盘上.exe文件在内存中的一份拷贝,但是FileBuffer无法直接在内存中运行,必须经过PE loader(装载器)装载以后成为ImageBuffer。ImageBuffer是FileBuffer的”拉伸”。即”.exe ① . e x e 首 地 址 ( 基 址 ) 为 0 \color{orchid}{①.exe首地址(基址)为0} ①.exe首地址(基址)为0–>FileBuffer ② F i l e B u f f e r 首 地 址 也 为 0 \color{orchid}{②FileBuffer首地址也为0} ②FileBuffer首地址也为0–>ImageBuffer ③ I m a g e B u f f e r 首 地 址 为 I m a g e B a s e \color{orchid}{③ImageBuffer首地址为ImageBase} ③ImageBuffer首地址为ImageBase” ④ 而 真 正 的 程 序 入 口 地 址 是 : I m a g e B a s e + A d d r e s s O f E n t r y P o i n t ( O E P ) \color{orchid}{④而真正的程序入口地址是:ImageBase + AddressOfEntryPoint(OEP)} ④而真正的程序入口地址是:ImageBase+AddressOfEntryPoint(OEP) ↩︎