您的位置:首页 > 编程语言

PE文件结构(懒的写博客我直接贴代码还不行么!)

2016-05-14 09:30 323 查看
1.常见PE文件
可执行文件:EXE,SCR,COM
驱动程序:SYS,VSD
库文件:DLL,OCX,CPL,DRV
对象文件:OBJ

2.PE32(32位)、PE32+或者PE+(64位)

3.PE组成:
DOS头
DOS存根
NT头
节区头(代码段)
节区头(数据段)
节区头(资源段)
节区(代码段)
节区(数据段)
节区(资源段)

4.VA(virtual address:虚拟地址)&RVA(relative virtual address:相对虚拟地址)
VA=RVA+ImageBase(映象基址)

5.DOS头
IMAGE_DOS_HEADER STRUCT

{

+0h WORD e_magic    // Magic DOS signature MZ(4Dh 5Ah)      DOS可执行文件标记

+2h WORD e_cblp    // Bytes on last page of file            最后一页大小

+4h WORD e_cp    // Pages in file                           文件页数

+6h WORD e_crlc    // Relocations

+8h WORD e_cparhdr   // Size of header in paragraphs        头的段大小

+0ah WORD e_minalloc   // Minimun extra paragraphs needs    最小额外段需求

+0ch WORD e_maxalloc  // Maximun extra paragraphs needs     最大额外段需求

+0eh WORD e_ss            // intial(relative)SS value       DOS代码的初始化堆栈SS

+10h WORD e_sp     // intial SP value                       DOS代码的初始化堆栈指针SP

+12h WORD e_csum     // Checksum                            校验和

+14h WORD e_ip     // intial IP value                       DOS代码的初始化指令入口[指针IP]

+16h WORD e_cs     // intial(relative)CS value              DOS代码的初始堆栈入口

+18h WORD e_lfarlc     // File Address of relocation table  重定位表的文件地址

+1ah WORD e_ovno         // Overlay number

+1ch WORD e_res[4]      // Reserved words                       保留字

+24h WORD e_oemid      // OEM identifier(for e_oeminfo)

+26h WORD e_oeminfo   // OEM information;e_oemid specific

+29h WORD e_res2[10]        // Reserved words                   保留字

+3ch DWORD e_lfanew         //Offset to start of PE header      NT头地址

} IMAGE_DOS_HEADER ENDS

6.DOS存根
DOS存根是16位的汇编指令,用以在DOS中运行

7.NT头
typedef struct _IMAGE_NT_HEADERS {
+00h DWORD Signature;  //PE签名 固定为 "PE"00(0X50450000)
+04h IMAGE_FILE_HEADER FileHeader;  //文件头 大小为0xF8
+18h IMAGE_OPTIONAL_HEADER32 OptionalHeader;//可选头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

//文件头
typedef struct _IMAGE_FILE_HEADER {
+00h WORD    Machine;  //CPU机器码,I386对应为0x014c
+02h WORD    NumberOfSections; //节区数量
+04h DWORD   TimeDateStamp;  //PE文件的创建时间,一般有连接器填写。
+08h DWORD   PointerToSymbolTable; //COFF文件符号表在文件中的偏移。
+0ch DWORD   NumberOfSymbols;  //符号表的数量。
+10h WORD    SizeOfOptionalHeader;  //可选头大小
+12h WORD    Characteristics;  //文件属性标志(用或计算) 常见:0x0002:可执行文件 0x2000:DLL文件
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

//可选头,以32位下可选头为例
typedef struct _IMAGE_OPTIONAL_HEADER {
+00h WORD    Magic;  //可选头类型
+02h BYTE    MajorLinkerVersion; //连接器版本号
+03h BYTE    MinorLinkerVersion;  //连接器版本号
+04h DWORD   SizeOfCode;  //代码段的长度,如果有多个代码段,则是代码段长度的总和。
+08h DWORD   SizeOfInitializedData;  //初始化的数据长度。
+0ch DWORD   SizeOfUninitializedData;  //未初始化的数据长度。
+10h DWORD   AddressOfEntryPoint;  //程序的EP(RVA表示)
+14h DWORD   BaseOfCode;  //代码段起始地址的RVA。
+18h DWORD   BaseOfData;  //数据段起始地址的RVA。
+1ch DWORD   ImageBase;  //映象(加载到内存中的PE文件)的基地址,这个基地址是建议,对于DLL来说,如果无法加载到这个地址,系统会自动为其选择地址。
+20h DWORD   SectionAlignment; //节对齐,PE中的节被加载到内存时会按照这个域指定的值来对齐,比如这个值是0x1000,那么每个节的起始地址的低12位都为0。
+24h DWORD   FileAlignment;//节在文件中按此值对齐,SectionAlignment必须大于或等于FileAlignment。
+28h WORD    MajorOperatingSystemVersion;  //操作系统版本号
+2ah WORD    MinorOperatingSystemVersion;  //操作系统版本号
+2ch WORD    MajorImageVersion;  //映象的版本号,这个是开发者自己指定的,由连接器填写。
+2eh WORD    MinorImageVersion;  //映象的版本号,这个是开发者自己指定的,由连接器填写。
+30h WORD    MajorSubsystemVersion;  //所需子系统版本号。
+32h WORD    MinorSubsystemVersion;  //所需子系统版本号。
+34h DWORD   Win32VersionValue;  //保留,必须为0。
+38h DWORD   SizeOfImage;  //映象的大小,PE文件加载到内存中空间是连续的,这个值指定占用虚拟空间的大小。
+3ch DWORD   SizeOfHeaders;  //所有文件头(包括节表)的大小,这个值是以FileAlignment对齐的。
+40h DWORD   CheckSum;  //映象文件的校验和。
+44h WORD    Subsystem;  //运行该PE文件所需的子系统(1.系统驱动,2.窗口应用程序,3.控制台应用)
+46h WORD    DllCharacteristics;  //DLL的文件属性
+48h DWORD   SizeOfStackReserve;  //运行时为每个线程栈保留内存的大小。
+4ch DWORD   SizeOfStackCommit;  //运行时每个线程栈初始占用内存大小。
+50h DWORD   SizeOfHeapReserve;  //运行时为进程堆保留内存大小。
+54h DWORD   SizeOfHeapCommit;  //运行时进程堆初始占用内存大小。
+58h DWORD   LoaderFlags;  //保留,必须为0。
+5eh DWORD   NumberOfRvaAndSizes;  //数据目录的项数,即下面这个数组的项数
+60h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];  //数据目录,这是一个数组,第i项含义在下边
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef struct   {
+00h DWORD   VirtualAddress;  //RVA
+04h DWORD   Size; //大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

8.节区头
typedef struct _IMAGE_SECTION_HEADER {
+00h BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];      //8个字节的区块名
+08h union {                                     //区块尺寸
DWORD   PhysicalAddress;
DWORD   VirtualSize;
} Misc;
+0ch DWORD   VirtualAddress;                     //区块的RVA地址
+10h DWORD   SizeOfRawData;                      //文件对齐后的尺寸
+14h DWORD   PointerToRawData;                   //文件偏移
+18h DWORD   PointerToRelocations;
+1ch DWORD   PointerToLinenumbers;
+20h WORD    NumberOfRelocations;
+22h WORD    NumberOfLinenumbers;
+24h DWORD   Characteristics;                    //区块的属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

RVA与RAW换算(内存地址与文件偏移的转换)
RAW=RVA-VirtualAddress+PointerToRawData

9.IAT(Import Address Table:导入地址表):
INT和IAT是以NULL为结束的长整型数组,保存的是_IMAGE_IMPORT_BY_NAME, IMAGE_THUNK_DATA 的地址
_IMAGE_IMPORT_DESCRIPTOR:结构体中记录着PE文件要导入哪些库文件
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD   Characteristics;            //
DWORD   OriginalFirstThunk;         // INT地址(RVA)
};
DWORD   TimeDateStamp;                  //
DWORD   ForwarderChain;                 //
DWORD   Name;                           // RVA,指向字符串,是这个可执行文件的名字。例如"ACE.dll"
DWORD   FirstThunk;                     // IAT地址(RVA)
} IMAGE_IMPORT_DESCRIPTOR;

typedef struct _IMAGE_IMPORT_BY_NAME {
WORD    Hint; ///该函数的导出序数
BYTE    Name[1]; ///该函数的名字
} `, *PIMAGE_IMPORT_BY_NAME;

typedef struct _IMAGE_THUNK_DATA32 {
union {
DWORD ForwarderString;      // 一个RVA地址,指向forwarder string
DWORD Function;             // PDWORD,被导入的函数的入口地址
DWORD Ordinal;              // 该函数的序数
DWORD AddressOfData;        // 一个RVA地址,指向IMAGE_IMPORT_BY_NAME
} u1;
} IMAGE_THUNK_DATA32;
IMAGE_THUNK_DATA64与IMAGE_THUNK_DATA32的区别,仅仅是把DWORD换成了64位整数。

10.EAT

typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;                     //模块的内部名称,如果DLL文件的名字被用户改了,那么PE加载器会使用这个内部名称
DWORD Base;                     //序号的起始编号,注意:起始序号可以不为0
DWORD NumberOfFunctions;        //导出函数的个数
DWORD NumberOfNames;            //导出函数中具名函数个数
DWORD AddressOfFunctions;       //导出函数地址表所在地址(大小等于NumberOfNames)
DWORD AddressOfNames;           //导出函数名称表所在地址(大小等于NumberOfNames)
DWORD AddressOfNameOrdinals;    //导出函数序数表所在地址(大小等于NumberOfNames)
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  PE文件结构