分享
 
 
 

JIURL PE 格式学习总结(一)-- PE文件概述

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

零 前言

PE格式,是Windows的可执行文件的格式。Windows中的 exe文件,dll文件,都是PE格式。PE 就是Portable Executable 的缩写。Portable 是指对于不同的Windows版本和不同的CPU类型上PE文件的格式是一样的,当然CPU不一样了,CPU指令的二进制编码是不一样的。只是文件中各种东西的布局是一样的。

图 1.1

图1.1是 JIURL PEDUMP 打开 Win2K 中的 explorer.exe 的截图。JIURL PEDUMP 是我写的一个小工具,从文件开始的 Dos Header 一直到 Section Table,打开PE文件之后,点击相应结构,就会高亮显示文件中相应的部分。不过没有Sections。对了解 PE 格式有所帮助,可以很好的配合后面的介绍。可以到我的主页 http://jiurl.yeah.net 上下载。

一 PE文件格式概述

PE文件结构的总体层次分布如下所示

--------------

|DOS MZ Header |

|--------------|

|DOS Stub |

|--------------|

|PE Header |

|--------------|

|Section Table |

|--------------|

|Section 1 |

|--------------|

|Section 2 |

|--------------|

|Section ... |

|--------------|

|Section n |

--------------

1.1 DOS Header

PE文件最开始是一个简单的 DOS MZ header,它是一个 IMAGE_DOS_HEADER 结构。有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随 MZ Header 之后的 DOS Stub。

1.2 DOS Stub

DOS Stub 是一个有效的 DOS 程序。当程序在DOS下运时,输出象 "This program cannot be run in DOS mode" 这样的提示。在 图1.1中就可以看到字符串 "This program cannot be run in DOS mode"。这是编译器生成的默认stub程序。你也可以通过链接选项 /STUB:filename 指定任何有效的MS-DOS可执行文件来替换它。

1.3 PE Header

紧接着 DOS Stub 的是 PE Header。它是一个 IMAGE_NT_HEADERS 结构。其中包含了很多PE文件被载入内存时需要用到的重要域。执行体在支持PE文件结构的操作系统中执行时,PE装载器将从 DOS MZ header 中找到 PE header 的起始偏移量。因而?DOS stub 直接定位到真正的文件头 PE header。

1.4 Section Table

PE Header 接下来的数组结构 Section Table (节表)。如果PE文件里有5个节,那么此 Section Table 结构数组内就有5个成员,每个成员包含对应节的属性、文件偏移量、虚拟偏移量等。图1中的节表有4个成员。

1.5 Sections

PE文件的真正内容划分成块,称之为sections(节)。Sections 是以其起始位址来排列,而不是以其字母次序来排列。通过节表提供的信息,我们可以找到这些节。图1.1所示的 explorer.exe 中有4个节。程序的代码,资源等等就放在这些节中。

二 PE文件格式中的结构及其作用

这部分内容请参考下面的几篇文章,使用工具 JIURL PEDUMP 有助于快速了解。

大家不要因此,而失望不看,本文重点在后三篇,本篇只是为了有个交代,和介绍些相关内容。

注意,在WINNT.H中,有所有PE相关结构的定义。我们用到的结构定义都来自那里。

Microsoft Portable Executable and Common Object File Format Specification

MSDN

《Windows95系统程式设计大奥秘》

第8章 PE 与COFF OBJ 档案格式

Matt Pietrek 著 侯杰译

Iczelion的PE教程

PE学习笔记(一) rivershan

PE学习笔记(二) rivershan

Inside Windows

An In-Depth Look into the Win32 Portable Executable File Format

Matt Pietrek

已经被人翻译了。

Inside Windows

An In-Depth Look into the Win32 Portable Executable File Format

Matt Pietrek

三 几个要注意的问题

3.1 文件中大量的空白

在 PE Header结构 中的 OptionalHeader 结构中的成员 FileAlignment 的值是文件中节的对齐粒度,单位是字节,这个值应该是2的n次方,范围从512到64k。如果这里的值是512,那么PE文件中的节的长度都是512字节的整数倍,内容不够的部分用0填充。比如一个PE文件的 FileAlignment 为200h(十进制512),它的第一个节在400h处,长度为100h,那么从文件400h到500h中为这一节的内容,而文件对齐粒度是200h,所以为了使这一节长度为FileAlignment的整数倍,500h到600h会被用零填充。而下一个节的开始地址为600h。用16进制编辑器打开PE文件,就可以看到这种情况,PE文件头的内容结束到第一个节开始之间的地方,每一个节中内容结束到下一节开始的地方都会有大量的空白。VC6编译链接时默认的FileAlignment为1000h(4k),可以使用链接选项 /ALIGN:number 来改变这个值。比如把4k改成512时,可以明显减小生成文件的大小。

3.2 big-endian和little-endian

PE Header中的 FileHeader 的成员 Machine 中的值,根据WINNT.H中的定义,对于 Intel CPU 应该为 0x014c。但是你用16进制编辑器打开PE文件,看到这个WORD显示的却是 4c 01 。你看到的并没有错,你看到的 4c 01 就是 0x014c,只不过由于 intel cpu 是ittle-endian,所以显示出来是这样的。对于 big-endian 和 little-endian,请看下面的例子。

比如一个整形int变量。长为四个字节。

这个变量的地址比如为n。

则这个变量的4个字节地址分别为n,n+1,n+2,n+3。

当 这个整形变量 的值为 0x12345678 时,

对于 big-endian 来说

地址n+0的那个字节中的值为 0x12

地址n+1的那个字节中的值为 0x34

地址n+2的那个字节中的值为 0x56

地址n+3的那个字节中的值为 0x78

按如下方式就会显示为

n n+1 n+2 n+3

12 34 56 78

对于 ittle-endian 来说

地址n+0的那个字节中的值为 0x78

地址n+1的那个字节中的值为 0x56

地址n+2的那个字节中的值为 0x34

地址n+3的那个字节中的值为 0x12

按如下方式就会显示为

n n+1 n+2 n+3

78 56 34 12

Intel使用的是 ittle-endian 。

一个整形 int 变量 i,的地址是&i,那么这个i的四个字节是&i,&i+1,&i+2,&i+3。

可以用这样一个程序看到。

#include <stdio.h>

#include <conio.h>

void main()

{

int i;

char* p;

p=(char*)&i;

printf("i: ");

scanf("%x",&i);

printf("\n");

printf("&i+0: %x\n",*p);

printf("&i+1: %x\n",*(p+1));

printf("&i+2: %x\n",*(p+2));

printf("&i+3: %x\n",*(p+3));

printf("\n");

printf("&i-4: %x\n",*(p-4));

printf("&i-3: %x\n",*(p-3));

printf("&i-2: %x\n",*(p-2));

printf("&i-1: %x\n",*(p-1));

printf("\n");

printf("&i+4: %x\n",*(p+4));

printf("&i+5: %x\n",*(p+5));

printf("&i+6: %x\n",*(p+6));

printf("&i+7: %x\n",*(p+7));

getch();

}

当我们输入 12345678 的时候可以看到,输出

i: 12345678

&i+0: 78

&i+1: 56

&i+2: 34

&i+3: 12

&i-4: 7c

&i-3: ffffffff

&i-2: 12

&i-1: 0

&i+4: ffffffc0

&i+5: ffffffff

&i+6: 12

&i+7: 0

正是&i,&i+1,&i+2,&i+3这四个字节中储存了i的值。

对于int,WORD,DWORD等等都要注意 big-endian 和 little-endian 。

3.3 RVA (Relative Virtual Address) 相对虚拟地址

RVA是一个简单的相对于PE载入点的内存偏移。比如,PE载入点为0X400000,那么代码节中的地址0X401000的RVA为(target address) 0x401000 - (load address)0x400000 = (RVA)0x1000.换句话说 RVA是0x1000,载入点为0X400000,那么该RVA的在内存中的实际地址就是0X401000。注意一下RVA是指内存中,不是指文件中。是指相对于载入点的偏移而不是一个内存地址,只有RVA加上载入点的地址,才是一个实际的内存地址。

3.4 三种不同的地址

PE的各种结构中,涉及到很多地址,偏移。有些是指在文件中的偏移,有的是指在内存中的偏移。一定要搞清楚,这个地址或者是偏移,是指在文件中,还是指在内存中。第一种,文件中的地址。比如用16进制编辑器打开PE文件,看到的地址(偏移)就是文件中的地址,我们使用某个结构的文件地址,就可以在文件中找到该结构。第二种,文件被整个映射到内存时,比如某些PE分析软件,把整个PE文件映射到内存中,这时是内存中的地址,如果知道某一个结构在文件中的地址的话,那么这个PE文件被映射到内存之后该结构的在内存中的地址,可以用文件中的地址加上映射内存的地址,就可以得到在该结构内存中的地址。第三种,执行PE时,PE文件会被载入器载入内存,这时经常需要的是RVA。比如知道一个结构的RVA,那么载入点加上RVA就可以得到内存中该结构的实际地址。比如,某个程序,我们用16进制编辑器打开它,看到PE Header开始在16进制编辑器显示为000000C8的地方。于是我们在16进制编辑器显示为000000FC的地方找到了OptionalHeader的ImageBase,值为400000h,那么当这个程序被执行时,如果内存中400000h处没有使用,该程序就会被载入到那里。而我用CreateFileMapping将这个PE文件映射到内存中时,可以得到块内存的地址为5505024。对于映射入内存的这个PE文件,我们就可以在内存中000000FCh+05505024h=5505120处找到这个PE的OptionalHeader的ImageBase。

3.5 几个重要结构的说明

PE Header 的 FileHeader 的 NumberOfSections:这是一个很重要的字段,用来确定文件中节的数目。

PE Header 的 OptionalHeader 的 IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]:一个IMAGE_DATA_DIRECTORY 结构数组。到目前为止这个数组的长度是固定的,有16个元素,这16个元素分别代表

#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

每个元素是一个IMAGE_DATA_DIRECTORY结构,IMAGE_DATA_DIRECTORY定义如下。

typedef struct _IMAGE_DATA_DIRECTORY {

DWORD VirtualAddress;

DWORD Size;

} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

第一个字段是一个RVA,第二个字段是一个大小。

Section Table 节表紧跟在OptionalHeader之后,是一个IMAGE_SECTION_HEADER结构的数组。该数组中成员的个数由 File Header (IMAGE_FILE_HEADER) 结构中 NumberOfSections 域的域值来定。节表中的成员是IMAGE_SECTION_HEADER 结构,IMAGE_SECTION_HEADER 结构的长度固定,长40个字节。整个Section Table 的长度不固定,等于 NumberOfSections*sizeof(IMAGE_SECTION_HEADER)。IMAGE_SECTION_HEADER 结构中,

VirtualAddress:本节的RVA(相对虚拟地址)。

PointerToRawData:这是本节基于文件的偏移量。

3.6 DOS MZ Header 中的 MZ

MZ是MZ格式的主要作者 Mark Zbikowski 的名字的缩写。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有