您的位置:首页 > 其它

PE文件结构-学习笔记

2009-08-12 08:05 447 查看
“稀饭”大佬给我发的一份资料,我觉得在学习汇编前还是有必要了解一下PE文件结构。

 

这张图很清楚:

+----------------------+------------------
|      Dos Header      |64字节(0x40)
|                      |
+----------------------+------------------
|      Dos Stub        |
|                      |
+----------------------+------------------
|                      |--------------->+----------------------+
|                      |                |       Signature      |
|                      |                |                      |
|      Pe Header       |248字节(0xF8)   +----------------------+
|                      |                |      File Header     |
|                      |                |                      |
|                      |                +----------------------+
|                      |                |     Optional Header  |--------------->+----------------------+
+----------------------+----------------|                      |                |        Magic         |
|   section headers  1 |40字节(0x28)    +----------------------+                |                      |
|                      |                                                        +----------------------+
+----------------------+----------------                                        |        . . .         |
|   section headers  2 |                                                        |                      |
|                      |                                                        +----------------------+
+----------------------+                                                        |    DataDirectory     |
|   .................. |                                 +----------------------|                      |
|                      |                                 |                      +----------------------+
+----------------------+                                 |
|      section 1       |                                 |
|                      |                      +----------------------+
+----------------------+                      |   Export Directory   |8字节(0x08)
|      section 2       |                      +----------------------+
|                      |                      |   Import Directory   |
+----------------------+                      +----------------------+
|   .................. |                      |        . . .         |
|                      |                      +----------------------+
+----------------------+                      |        . . .         |
+----------------------+
   

 
//sdk winnt.h

//dos header///////////////////////////////////////////////////////////////////////////
#define IMAGE_DOS_SIGNATURE 0x5A4D      // MZ

typedef struct _IMAGE_DOS_HEADER        // DOS .EXE header
{
WORD   e_magic;                     // +0x00 Magic number  魔法数字 "MZ" *
WORD   e_cblp;                      // +0x02 Bytes on last page of file 文件最后一页的字节数
WORD   e_cp;                        // +0x04 Pages in file 文件的页数
WORD   e_crlc;                      // +0x06 Relocations 重定位
WORD   e_cparhdr;                   // +0x08 Size of header in paragraphs 段中头的大小
WORD   e_minalloc;                  // +0x0a Minimum extra paragraphs needed 需要的最少额外段
WORD   e_maxalloc;                  // +0x0c Maximum extra paragraphs needed 需要的最多额外段
WORD   e_ss;                        // +0x0e Initial (relative) SS value 初始的(相对的)SS寄存器值
WORD   e_sp;                        // +0x10 Initial SP value 初始的SP寄存器值
WORD   e_csum;                      // +0x12 Checksum 校验和
WORD   e_ip;                        // +0x14 Initial IP value 初始的IP寄存器值
WORD   e_cs;                        // +0x16 Initial (relative) CS value 初始的(相对的)CS寄存器值
WORD   e_lfarlc;                    // +0x18 File address of relocation table 重定位表在文件中的地址
WORD   e_ovno;                      // +0x1a Overlay number 交叠数
WORD   e_res[4];                    // +0x1c Reserved words 保留
WORD   e_oemid;                     // +0x24 OEM identifier (for e_oeminfo)
WORD   e_oeminfo;                   // +0x26 OEM information; e_oemid specific
WORD   e_res2[10];                  // +0x28 Reserved words 保留
LONG   e_lfanew;                    // +0x3c File address of new exe header 新exe头在文件中的地址 *
// +0x40
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; // size 64字节(0x40)

///////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////


 

///////////////////////////////////////////////////////////////////////////////////////
//dos stub
sizeof(dos stub) = (大小不固定,因便宜器而改变)
DOS stub实际上是个有效的 EXE,在不支持 PE文件格式的操作系统中,它将简单显示一个错误提示,
类似于字符串 "This program requires Windows" 或者程序员可根据自己的意图实现完整的 DOS代码。
通常我们也不对 DOS stub 太感兴趣: 因为大多数情况下它是由汇编器/编译器自动生成。
通常,它简单调用中断21h服务9来显示字符串"This program cannot run in DOS mode"。
//////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////
//sdk winnt.h

//pe header
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;                       // +0x00 pe文件签(4Byte)名 ASCII="pe/0/0" *
IMAGE_FILE_HEADER FileHeader;          // +0x04 PE文件头(IMAGE_FILE_HEADER)
IMAGE_OPTIONAL_HEADER OptionalHeader;  // +0x18 PE文件可选头(IMAGE_OPTIONAL_HEADER)
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;        // size 248字节(0xF8)

//file header
typedef struct _IMAGE_FILE_HEADER {
WORD    Machine;                           // +0x00 机器类型对于intel 386=0x014c *
WORD    NumberOfSections;                  // +0x02 文件节数目 *
DWORD   TimeDateStamp;                     // +0x04 时间戳文件创建的时间
DWORD   PointerToSymbolTable;              // +0x08 用于调试
DWORD   NumberOfSymbols;                   // +0x0c 用于调试
WORD    SizeOfOptionalHeader;              // +0x10 指明IMAGE_OPTIONAL_HEADER的大小 *
WORD    Characteristics;                   // +0x12 特征集合 *
// +0x14
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;      // size 20字节(0x14)

//optional header
typedef struct _IMAGE_OPTIONAL_HEADER
{
WORD    Magic;                        	// +0x00 魔法数字 * 0x010B
BYTE    MajorLinkerVersion;          	// +0x02 连接器主版本号
BYTE    MinorLinkerVersion;          	// +0x03 连接器副版本号
DWORD   SizeOfCode;                   	// +0x04 可执行代码的大小
DWORD   SizeOfInitializedData;        	// +0x08 已初始化数据的大小
DWORD   SizeOfUninitializedData;      	// +0x0c 未初始化数据的大小
DWORD   AddressOfEntryPoint;          	// +0x10 入口点地址 *
DWORD   BaseOfCode;                   	// +0x14 可执行代码的偏移值(“代码基址”)
DWORD   BaseOfData;                   	// +0x18 已初始化数据的偏移值(“数据基址”)
DWORD   ImageBase;                    	// +0x1c 映象文件基址 *
DWORD   SectionAlignment;             	// +0x20 内存对其 * 2^n
DWORD   FileAlignment;                	// +0x24 文件对其 * 2^n
WORD    MajorOperatingSystemVersion;  	// +0x28 OS主版本号
WORD    MinorOperatingSystemVersion;  	// +0x2a OS副版本号
WORD    MajorImageVersion;            	// +0x2c 映象文件主版本号
WORD    MinorImageVersion;            	// +0x2e 映象文件副版本号
WORD    MajorSubsystemVersion;        	// +0x30 子系统主版本号 *
WORD    MinorSubsystemVersion;        	// +0x32 子系统副版本号
DWORD   Win32VersionValue;            	// +0x34 Win32版本值
DWORD   SizeOfImage;                  	// +0x38 映像文件大小   *
DWORD   SizeOfHeaders;                	// +0x3c 所有类型的头的大小的总和 * (指向第一个节)
DWORD   CheckSum;                     	// +0x40 校验和
WORD    Subsystem;                    	// +0x44 子系统 *
WORD    DllCharacteristics;           	// +0x46 DLL标记(0非dll文件,1 dll文件) *
DWORD   SizeOfStackReserve;           	// +0x48 保留栈的大小
DWORD   SizeOfStackCommit;            	// +0x4c 指定栈的大小
DWORD   SizeOfHeapReserve;            	// +0x50 保留堆的大小
DWORD   SizeOfHeapCommit;             	// +0x54 指定堆的大小
DWORD   LoaderFlags;                  	// +0x58 加载器标志
DWORD   NumberOfRvaAndSizes;          	// +0x5c RVA大小的总和 *
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // +0x60
// +0xe0
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;  //size 224字节(0xE0)

typedef struct _IMAGE_DATA_DIRECTORY
{
DWORD   VirtualAddress;  // +0x00 RVA
DWORD   Size;            // +0x04 The size in bytes
// +0x08
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

0 [       0] RVA [size] of Export Directory
208 [      28] RVA [size] of Import Directory
0 [       0] RVA [size] of Resource Directory
0 [       0] RVA [size] of Exception Directory
0 [       0] RVA [size] of Certificates Directory
0 [       0] RVA [size] of Base Relocation Directory
0 [       0] RVA [size] of Debug Directory
0 [       0] RVA [size] of Architecture Directory
0 [       0] RVA [size] of Special Directory
0 [       0] RVA [size] of Thread Storage Directory
0 [       0] RVA [size] of Load Configuration Directory
0 [       0] RVA [size] of Bound Import Directory
1E0 [       8] RVA [size] of Import Address Table Directory
0 [       0] RVA [size] of Delay Import Directory
0 [       0] RVA [size] of Reserved Directory
0 [       0] RVA [size] of Reserved Directory
//////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////
//sdk winnt.h

//Section header

#define IMAGE_SIZEOF_SHORT_NAME              8       //定义一个常量

typedef struct _IMAGE_SECTION_HEADER {
UCHAR   Name[IMAGE_SIZEOF_SHORT_NAME];           // +0x00 名字数组
union {                                          //       共用体标志
ULONG   PhysicalAddress;                 //       节的物理地址
ULONG   VirtualSize;                     // +0x08 节的虚拟大小 <--(文件中的值)
} Misc;
ULONG   VirtualAddress;                          // +0x0c 节被载入到的地址空间中的虚拟地址
ULONG   SizeOfRawData;                           // +0x10 下个FileAlignment'倍数的大小
ULONG   PointerToRawData;                        // +0x14 位于文件中的节身的位置的偏移量,如果是0,节数据不包含在文件内,在加载时被确定
ULONG   PointerToRelocations;                    // +0x18 重定位指针
ULONG   PointerToLinenumbers;                    // +0x1c 行数指针
USHORT  NumberOfRelocations;                     // +0x20 重定位数目
USHORT  NumberOfLinenumbers;                     // +0x22 行数数目
ULONG   Characteristics;                         // +0x24 定义节的特征
// +0x28
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;      // size 40字节(0x28)

值                 定义
0x00000020          代码节
0x00000040          已初始化数据节
0x00000080          未初始化数据节
0x04000000          不可缓存节
0x08000000          不可分页节
0x10000000          共享节
0x20000000          可执行节
0x40000000          可读节
0x80000000          可写节


 

////////////////////////////////////////////////////////////////////////////////////////
注意:
如果一个PE文件里,对应了N个节,那么IMAGE_SECTION_HEADER结构也是对应N个
另外为了标记IMAGE_SECTION_HEADER结构已经结束了,都会在最后一个IMAGE_SECTION_HEADER附加一个
成员全部为零的IMAGE_SECTION_HEADER结构。
WINXP下运行PE的程序最小要求IMAGE_SECTION_HEADER为>=2,WIN2k则没有这个要求

//IMAGE_IMPORT_DESCRIPTOR

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD   Characteristics;            // 0 for terminating null import descriptor
DWORD   OriginalFirstThunk;         // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
};
DWORD   TimeDateStamp;                  // 0 if not bound,
// -1 if bound, and real date/time stamp
//     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)

DWORD   ForwarderChain;                 // -1 if no forwarders
DWORD   Name;
DWORD   FirstThunk;                     // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;

DWORD   OriginalFirstThunk     //它是一个RVA(32位),指向一个以0结尾的、由IMAGE_THUNK_DATA(换长数据)的RVA构成的数组,其每个IMAGE_THUNK_DATA(换长数据)元素都描述一个函数。此数组永不改变。
DWORD   TimeDateStamp          //它是一个具有好几个目的的32位的时间戳。让我们先假设时间戳为0,一些高级的情况将在以后处理。
DWORD   ForwarderChain         //它是输入函数列表中第一个中转的、32位的索引。中转也是高级的东东。对初学者先将所有位设为-1。
DWORD   Name                   //它是一个DLL文件的名称(0结尾的ASCII码字符串)的、32位的RVA。
DWORD   FirstThunk             //它也是一个RVA(32位),指向一个0结尾的、由IMAGE_THUNK_DATA(换长数据)的RVA构成的数组,其每个IMAGE_THUNK_DATA(换长数据)元素都描述一个函数。此数组是输入地址表的一部分,并且可以改变。


 

注意:IMAGE_IMPORT_DESCRIPTOR结构个数是和需要应入的DLL文件个数对应的,比如应入了N个DLL文件,那么就有N个IMAGE_IMPORT_DESCRIPTOR结构
最后用一个成员全为零的IMAGE_IMPORT_DESCRIPTOR结构来标记结束。

 

 
typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString;      // PBYTE
DWORD Function;             // PDWORD
DWORD Ordinal;
DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;


 

对应一个32位的值

DWORD ForwarderString;     标记位对应一个比特位,当为1时候,表示函数用序号引入,为0时,表示用名字引入
注意:IMAGE_THUNK_DATA32结构个数是和需要引入函数个数对应的,比如引入了N个函数,那么就有N个IMAGE_THUNK_DATA32结构
最后用一个成员全为零的IMAGE_THUNK_DATA32结构来标记结束。

typedef struct _IMAGE_IMPORT_BY_NAME {
WORD    Hint;                   //Hint字段的内容是可选的,如果它不是0,则它也表示函数的序号
BYTE    Name[1];                //变长数组,保存的是一个以NULL结尾的字符串,也就是函数名。
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;


 

////////////////////////////////////////////////////////////////////////////////////////

 

 

本文来自稀饭:

http://tmdnet.nothave.com/src/Portable-Executable/2.PE/PE.txt
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息