深入浅出Windows PE(一) PE文件头
PE文件头记录了PE文件中的所有数据组织方式,它类似于一本书的目录,通过目录我们可以快速定位到某个具体的章节;通过PE文件头部分对某些数据结构的描述,我们也可以定位到那些不在文件头部的信息,比如导入表数据,导出表数据,资源表数据等。
1.与PE有关的基本概念
地址
PE中涉及的地址有四类,他们分别是:
* 虚拟内存地址(VA)
* 相对虚拟内存地址(RVA)
* 文件偏移地址(FOA)
* 特殊地址
想要了解这些概念,首先简单地了解一些Win32对内存的管理,以及分页机制的原理。
32位CPU的寻址能力为4GB,但有些用户的物理内存达不到这个值。于是操作系统和CPU的内存管理单元共同作用,为用户提供了虚拟内存的管理机制。即分页机制。该机制可以让用户感觉自己好像在使用4GB的内存。
分页机制的基本原理是:
操作系统假设一个进程独立拥有4GB内存,按照某个固定的大小(如4KB)将这个4GB空间分成N(1M)个页。在某一时刻,所有这些页只有一部分和物理内存是对应的。(所以这种机制允许物理内存比4GB小)。没有物理内存对应的页面被标记为脏(dirty)的页面,一般存储在一个名为“交换文件”的磁盘文件中。在Windows XP系统中,交换文件为pagefile.sys,它位于系统盘的根目录,是一个系统隐藏文件。当系统需要读取未在内存中的数据时,这部分数据会将内存中不经常读写的页面交换出内存,而把要读取的,位于交换文件中的页换进内存。
通过这种存取机制可以让一个进程拥有比实际内存大得多的内存。利用这种机制管理的内存称为虚拟内存。
虚拟内存地址
用户的PE文件被操作系统加载进内存后,PE对应的进程支配了自己独立的4GB虚拟空间。这个空间中定位的地址称为虚拟内存地址(Virtual Adress,VA),所以虚拟现实内存地址范围是00000000h~0ffffffffh。在PE中,进程本身的VA被解释为:进程基地址 + 相对虚拟内存地址。
相对虚拟内存地址
一个进程被操作系统加载到虚拟内存空间后,其相关的动态链接库也会被加载。这些同时加载到进程地址空间的文件被称为模块。每一个模块在加载时都会有一个基地址,也就是预先告诉操作系统:它会占用4GB空间的哪个部分(即从哪里开始存储该模块)。不同模块的基地址一般是不同的,如果两个模块的基地址相同,就有操作系统来决定这两个模块在虚拟空间中的具体位置。
相对虚拟内存地址(Reverse Virtual Address,RVA)是相对于基地址的偏移,即RVA是虚拟内存中用来定位某个特定位置的地址,该地址的值是这个特定位置距离某个基地址的偏移量,所以说RVA是针对某个某块而存在的。
文件偏移地址
文件偏移地址(File Offset Address,FOA)和内存无关,它是值某个位置距离文件头的偏移。
特殊地址
在PE结构中还有一种特殊地址,其计算方法并不是从文件头算起,也不是从内存的某个模块算起,而是从某个特定的位置算起。这种地址在PE结构中很少见。
指针
PE数据结构中的指针的定义:如果数据结构中某个字段存储的值为一个地址,那么这个字段就是一个指针。
数据目录
Windows下可执行文件是PE中的一种,这种文件除了包含代码及数据段的相关数据以外,还包含许多与文件执行有关的其他数据结构,比如引用外部函数的信息,PE程序的图标,内部函数导出表等。
PE中有一个数据结构成为数据目录,其中记录了所有可能的数据类型。这些类型中,目前已定义的有15种,包括导出表,导入表,资源表,异常表,属性证书表,重定位表,调试数据,Architecture,Global Ptr,线程局部存储,加载配置表,绑定导入表,IAT,延迟导入表,CLR运行时头部。
节
无论是结构化程序设计,还是面向对象程序设计,都提倡程序与数据的独立性,因此,程序中的代码和数据通常是分开存放的。为了保证程序执行安全,保证内核的稳定,Windows操作系统通常对不同用途的数据设置不同的访问权限。比如,代码段中的字节码在程序运行的过程中,一般不允许用户进行修改,数据段则允许在程序运行中读和写,常量只能读等。Windows操作系统在加载可执行程序时,会为这些具有不同属性的数据分别分配标记有不同属性的页面(当然,相同属性的数据可能会被放到同一个页面),以确保程序运行时的安全。正是基于这个原因,PE中才会出现所谓的节的概念。
节是存放不同类型数据的地方(比如代码,数据,常量,资源等)的地方,不同的节具有不同的访问权限。节是PE文件中存放代码或者数据的基本单元。例如,一个目标文件的所有代码可以组合成单个节,或者每个函数独占一个节。增加节的数目会增加文件开销,但是链接器在链接代码时会有更大的选择余地。一个节的所有原始数据必须被加载到连续的内存空间中。
从操作系统加载的角度来看,节是相同属性数据的组合。与数据目录不同的是,尽管有些数据类型不同,分别属于不同的数据目录,但由于其访问属性相同,便被归到同一个节中。这个节最终可能会占用一个或者多个页面;但无论多少个,所有相关页面都被赋予相同的页属性。这些属性包括只读,只写,可读,可写等。
汇编语言中以“.”开头的一些伪指令其实就是在声明不同的数据类型。比如".data"声明的是初始化数据,".data?"声明的是未初始化数据,".code"声明的是可执行的代码等。Windows操作系统在装载PE文件时会对这些数据执行抛弃,合并,新增,复制等操作。这些不同的操作交叉组合导致了内存中的节和文件中的节会出现很大的不同。例如“.data?”的数据在磁盘中不存在,但是在内存中存在,而".reloc"重定位表数据却恰恰相反。
对齐
对齐这个概念并非只在PE结构中出现,许多文件格式都会有对齐的要求。有的对齐是为了美观,有的对齐则是为了效率。PE中规定了三类对齐:数据在内存中的对齐,数据在文件中的对齐,资源文件中资源数据的对齐。
内存对齐
由于Windows操作系统对内存属性的设置以页为单位,所以通常情况下,节在内存中的对齐单位必须至少是一个页的大小。对32位的Windows XP系统来说,这个值是4kb。
文件对齐
相对来说,节在磁盘文件中的对齐尺寸没有那么严格。为了提高磁盘利用率,通常情况下,定义节在文件中的对齐单位要远小于内存对齐的单位;通常会以一个物理扇区的大小作为对齐粒度的值,即512字节,十六进制表示200h。
出于节约资源考虑,操作系统允许节在内存中和文件中的对齐尺寸不一致。这就直接造成了PE文件在文件中和内存中的大小也会不一致。通常情况下,PE在内存中的尺寸要比文件中的尺寸大。用户可以自己定义这些对齐的值。
资源数据对齐
资源文件中,资源字节码部分一般要求以双子方式对齐。
PE文件结构
PE经历了从16位系统到32位系统的过渡,因此,32位系统下的每一个PE文件都可以在16位系统下运行。尽管PE文件的结构一样,但从不同的角度来看其结构划分却不一样。
16位系统下的PE结构
DOS头部分的存在见证了PE的强大兼容性。为了保证与16位系统的兼容,在PE里依旧保留了16位系统的标准可执行程序执行时所必须的文件头部(DOS MZ头)和指令代码(DOS Stub)。
在16位系统下,PE结构可以大致分为两部分:DOS头和其他数据:
--------------------------------
DOS MZ头
-------------------------------- DOS头
DOS Stub
--------------------------------
PE 头
-------------------------------- 次要数据
PE 数据区域
--------------------------------
如上图所示,在16位的系统下,PE的四部分内容被重新组合成为两部分——可以在16位系统下运行的DOS头和次要数据。把Windows下的PE文件存储到DOS系统并运行,它就是DOS系统下的一个exe文件。
DOS头分为两部分:DOS MZ和DOS Stub(即指令字节码)。大部分情况下,这些指令实现的功能相当简单,根本不会涉及重定位信息。
DOS MZ头
在Windows的PE格式中,DOS MZ的定义如下:
IMAGE_DOS_HEADER STRUCT
e_magic WORD ? ;0000h - EXE标志,"MZ"
e_cblp WORD ? ;0002h - 最后(部分)页中的字节数
e_cp WORD ? ;0004h - 文件中的全部和部分页数
e_crlc WORD ? ;0006h - 重定位表中的指针数
e_cparhdr WORD ? ;0008h - 头部尺寸,以段落为单位
e_minalloc WORD ? ;000ah - 所需的最小附加段
e_maxalloc WORD ? ;000ch - 所需的最大附加段
e_ss WORD ? ;000eh - 初始的ss值
e_sp WORD ? ;0010h - 初始的sp值
e_csum WORD ? ;0012h - 补码校验值
e_ip WORD ? ;0014h - 初始的IP值
e_cs WORD ? ;0016h - 初始化CS值
e_lfarlc WORD ? ;0018h - 重定位表的字节偏移量
e_ovno WORD ? ;001ah - 覆盖号
e_res WORD 4 dup(?) ;001ch - 保留字
e_oemid WORD ? ;0024h - OEM标志符
e_oemif WORD ? ;0026h - OEM信息
e_res2 WORD 10 dup(?) ;0028h - 保留字
e_lfanew DWORD ? ;003ch - PE头相对于文件的偏移地址
IMAGE_DOS_HEADER ENDS
如上所示,红色部分在16位系统下是没有定义的。由于其开始的标志字为“MZ”(Mark Zbikowski,DOS操作系统的开发者之一),所以称它为“DOS MZ头”。
用OD反汇编产看DOS MZ字节码如下:
Dump - HelloWorld:00400000..00400FFF
Address Hex dump Decoded data Comments
00400000 /. 4D 5A ASCII "MZ" ; DOS_Signature[2] = "MZ"
00400002 |. 9000 DW 90 ; DOS_PartPag = 144.
00400004 |. 0300 DW 3 ; DOS_PageCnt = 3
00400006 |. 0000 DW 0 ; DOS_ReloCnt = 0
00400008 |. 0400 DW 4 ; DOS_HdrSize = 4
0040000A |. 0000 DW 0 ; DOS_MinMem = 0
0040000C |. FFFF DW 0FFFF ; DOS_MaxMem = 65535.
0040000E |. 0000 DW 0 ; DOS_RelSS = 0
00400010 |. B800 DW 0B8 ; DOS_ExeSP = 0B8
00400012 |. 0000 DW 0 ; DOS_ChkSum = 0
00400014 |. 0000 DW 0 ; DOS_ExeIP = 0
00400016 |. 0000 DW 0 ; DOS_RelCS = 0
00400018 |. 4000 DW 40 ; DOS_RelocOffset = 40
0040001A |. 0000 DW 0 ; DOS_Overlay = 0
0040001C |. 0000 DW 0 ; DOS_Reserved1[4] = 00000000
0040001E |. 0000 DW 0
00400020 |. 0000 DW 0
00400022 |. 0000 DW 0
00400024 |. 0000 DW 0 ; DOS_OEM_ID = 0
00400026 |. 0000 DW 0 ; DOS_OEM_Info = 0
00400028 |. 0000 DW 0 ; DOS_Reserved2[10.] = 00000000
0040002A |. 0000 DW 0
0040002C |. 0000 DW 0
0040002E |. 0000 DW 0
00400030 |. 0000 DW 0
00400032 |. 0000 DW 0
00400034 |. 0000 DW 0
00400036 |. 0000 DW 0
00400038 |. 0000 DW 0
0040003A |. 0000 DW 0
0040003C \. B000 DW 0B0 ; DOS_PEOffset = 0B0
DOS Stub
用DOS命令反汇编DOS Stub中的内容,得到的结果如下:
13B7:0140 0E PUSH CS ;将CS段地址给DS
13B7:0141 1F POP DS
13B7:0142 BA0E00 MOV DX,000E ;DS:DX指向要显示的字符串
13B7:0145 B409 MOV AH,09 ;调用9号中断,屏幕显示字符串
13B7:0147 CD21 INT 21
13B7:0149 B8014C MOV AX,4C01 ;调用4C号中断,正常退出程序
13B7:014C CD21 INT 21
13B7:014E 5468.. 数据区 'This program...' ;要显示的字符串
DOS Stub程序的功能很简单,通过调用21号中断的9号功能,实现在屏幕上输出一段字符串。这段字符串提示用户该程序为32位的PE文件,不能运行在DOS环境下。
32位系统下的PE结构
在16位系统中,PE头和PE数据部分被当成是次要数据;在32位系统中,刚好相反。即DOS头成为了次要数据。所谓次要,是针对DOS头不参与32位系统运行过程而言的。尽管该部分不参与运行,但也不能把这些数据从PE结构中除去。因为DOS MZ头中有一个字段非常重要,即IMAGE_DOS_HEADER.e_lfanew,没有它操作系统就定位不到标准的PE头部,可执行程序也会被操作系统认为是非法PE映像。
定位标准PE头
由于DOS Stub的长度不固定,导致DOS头也不是一个固定大小的数据结构。那么,在Windows PE中,既然把DOS头放在PE的起始位置,如何去定位后面的标准PE头的位置呢?字段e_lpanew即起这个作用。该字段的值是一个相对的偏移量,绝对定位需要加上DOS MZ头的基地址。
PE文件结构
在32位系统下,最重要的部分就是PE头和PE数据区:
---------------------------------------------------
DOS MZ头
--------------------------------------------------- DOS头
DOS Stub
---------------------------------------------------
PE头 PE头
---------------------------------------------------
节表
--------------------------------------------------- PE数据区
节内容
---------------------------------------------------
如上图所示,32位系统下的PE文件结构被划分为5个部分,包括:
DOS MZ头,DOS Stub,PE头,节表,节内容。
节表和节内容两部分就是PE数据区。DOS MZ头的大小是64个字节,PE头的大小456个字节(由于数据目录表项不一定是16个,所以准确地说,PE头也是一个大小不能确定的结构,该结构的实际大小由字段IMAGE_FILE_HEADER.SizeOfOptionalHeader来确定)。节表的大小也是不固定的,因为每个PE中节的数量是不确定的。每个节的描述信息则是个固定的值,共40个字节,节表是由不确定数量的节描述信息组成的,其大小等于节的数量 * 40,节的数量由字段IMAGE_FILE_HEADER.NumberOfSections来定义。DOS Stub和节内容都是大小固定的。
程序猿眼中的PE结构
在程序员眼中,PE文件格式是由许多数据结构组成的,数据结构是一系列有组织的数据集合:
---------------------------------------------------
IMAGE_DOS_HEADER(64)
---------------------------------------------------
....(DOS Stub大小不确定,但以某大小对齐)
---------------------------------------------------
Signature(4)
---------------------------------------------------
IMAGE_FILE_HEADER(20)
---------------------------------------------------
..........(88)
---------------------------------------------------
IMAGE_DATA_DIRECTORY(16*8)
---------------------------------------------------
IMAGE_OPTIONAL_HEADER32(216)
---------------------------------------------------
IMAGE_NT_HEADERS(240)
---------------------------------------------------
IMAGE_SECTION_HEADER(N*40)
---------------------------------------------------
.....(节内容不确定,单以某大小对齐)
---------------------------------------------------
如图所示,一个标准的PE文件一般由四大部分组成:
* DOS头
* PE头 (IMAGE_NT_HEADERS)
* 节表 (多个IMAGE_SECTION_HEADER结构)
* 节内容
其中,PE头的数据结构最为复杂。简单来说,PE头包括:
* 4个字节的标识符 (Signature)
* 20个字节的基本头信息 (IMAGE_FILE_HEADER)
* 216个字节的扩展头信息(IMAGE_OPTIONAL_HEADER32)
PE文件头部解析
DOS MZ头IMAGE_DOS_HEADER
在之前已经介绍过DOS MZ头,为了保证完整性,这里再重复一次:
IMAGE_DOS_HEADER STRUCT
e_magic WORD ? ;0000h - EXE标志,"MZ"
e_cblp WORD ? ;0002h - 最后(部分)页中的字节数
e_cp WORD ? ;0004h - 文件中的全部和部分页数
e_crlc WORD ? ;0006h - 重定位表中的指针数
e_cparhdr WORD ? ;0008h - 头部尺寸,以段落为单位
e_minalloc WORD ? ;000ah - 所需的最小附加段
e_maxalloc WORD ? ;000ch - 所需的最大附加段
e_ss WORD ? ;000eh - 初始的ss值
e_sp WORD ? ;0010h - 初始的sp值
e_csum WORD ? ;0012h - 补码校验值
e_ip WORD ? ;0014h - 初始的IP值
e_cs WORD ? ;0016h - 初始化CS值
e_lfarlc WORD ? ;0018h - 重定位表的字节偏移量
e_ovno WORD ? ;001ah - 覆盖号
e_res WORD 4 dup(?) ;001ch - 保留字
e_oemid WORD ? ;0024h - OEM标志符
e_oemif WORD ? ;0026h - OEM信息
e_res2 WORD 10 dup(?) ;0028h - 保留字
e_lfanew DWORD ? ;003ch - PE头相对于文件的偏移地址
IMAGE_DOS_HEADER ENDS
DOS MZ头的下面是DOS Stub头。整个DOS Stub是一个字节块,其内容随着链接时使用的链接器不同而不同,PE中并没有与之对应的结构。
PE头标识Signature
紧跟在DOS Stub后面的是PE头标识Signature。与大部分文件格式的头部结构一样,PE头部信息中有一个四字节的标识,该标志位于IMAGE_DOS_HEADER.e_lfanew指向的位置。其内容固定,对应于ASCII码的字符串“PE\0\0”。
标准PE头IMAGE_FILE_HEADER
标准PE头IMAGE_FILE_HEADER紧跟在PE头标识后,即位于IMAGE_DOS_HEADER的e_lfanew值+4的位置。由此开始的20个字节为数据结构标准PE头IMAGE_FILE_HEADER的内容。该结构在微软的官方文档中被称为标准通用对象文件格式(Common Object File Format,COFF)头。它记录了PE文件的全局属性,如该PE文件运行的平台,PE文件类型(是EXE文件还是DLL文件),文件中存在的节的总数等,其详细定义如下:
IMAGE_FILE_HEADER STRUCT
Machine WORD ? ;0004h - 运行平台
NumberOfSections WORD ? ;0006h - PE中节的数量
TimeDateStamp DWORD ? ;0008h - 文件创建日期和时间
PointerToSymbolTable DWORD ? ;000ch - 指向符号表(用于调试)
NumberOfSybols DWORD ? ;0010h - 符号表中的符号数量(用于调试)
SizeOfOptionalHeader WORD ? ;0014h - 扩展头结构的长度
Characteristics WORD ? ;0016h - 文件属性
IMAGE_FILE_HEADER ENDS
该结构常常用来判断PE文件是EXE类型还是DLL类型,不但可以通过该结构得到PE文件中节的总量,还可以当成对节区信息进行遍历操作的循环次数。
扩展PE头IMAGE_OPTIONAL_HEADER32
尽管从名字上看好像该部分数据是可选(Optional)的,但是在PE文件结构中,它却有着比标准PE头更多的内容,让人感觉似乎它才是真正的PE头。其详细定义如下:
IMAGE_OPTINAL_HEADER32 STRUCT
Magic WORD ? ;0018h - 魔术字107h = ROM Image, 10Bh = eex Image
MajorLinkerVersion BYTE ? ;001ah - 链接器版本号
MinorLinkerVersion BYTE ? ;001bh
SizeofCode DWORD ? ;001ch - 所有包含代码的节的总大小
SizeOfInitializedData DWORD ? ;0020h - 所有包含已初始化数据的节的总大小
SizeOfUnitializedData DWORD ? ;0024h - 所有含未初始化数据的节的大小
AddressOfEntryPoint DWORD ? ;0028h - 程序执行入口RVA
BaseOfCode DWORD ? ;002ch - 代码的节的起始RVA
BaseOfData DWORD ? ;0030h - 数据的节的起始RVA
ImageBase DWORD ? ;0034h - 程序的建议装载地址
SectionAlignment DWORD ? ;0038h - 内存中的节的对齐粒度
FileAligment DWORD ? ;003ch - 文件中的节的对齐粒度
MajorOperatingSystemVersion WORD ;0040h - 操作系统版本
MinorOperatingSystemVersion WORD ;0042h
MajorImageVersion WORD ? ;0044h - 该PE的版本号
MinorImageVersion WORD ? ;0046h
MajorSubsystemVersion WORD ? ;0048h - 所需子系统版本号
MinorSubsystemVersion WORD ? ;004ah
Win32VersionValue WORD ? ;004ch -未用
SizeofImage DWORD ? ;0050h - 内存中的整个PE映像尺寸
SizeofHeaders DWORD ? ;0054h - 所有的整个PE映像尺寸
CheckSum DWORD ? ;0058h - 校验和
Subsystem WORD ? ;005ch - 文件子系统
DllCharacteristics ? ;005eh - DLL文件特性
SizeofStackReserver DWORD ? ;0060h - 初始化时的栈大小
SizeofStackCommit DWORD ? ;0064h - 初始化时实际提交的栈大小
SizeofHeapReserve DWORD ? ;0068h - 初始化时保留的堆大小
SizeofHeapCommit DWORD ? ;006ch - 初始化时实际提交的堆大小
LoaderFlags DWORD ? ;0070h - 与调试有关
NumberOfRvaAndSize DWORD ? ;0074h - 下面的数据目录结构的项目数量
DataDirectory IMAGE_DATA_DIRCTORY 16 dup (<>) ;0078h - 数据目录
IMAGE_OPTIONAL_HEADER32 ENDS
文件执行时的入口地址,文件本操作系统装入内存后的默认基地址,以及节在磁盘和内存中的对齐等信息均可在此结构中找到。对该结构中的某些数值的随意改动会导致PE文件的加载或运行失败。
PE头IMAGE_NT_HEADERS
这个结构是广义上的PE头,在标准的PE文件中其大小为456个字节。它是之前提到的三个数据结构的组合,即IMAGE_NT_HEADERS=4个字节的PE标识 + IMAGE_FILE_HEADER + IMAGE_OPTIONAL_HEADER32
数据目录项IMAGE_DATA_DIRECTORY
IMAGE_OPTIONAL_HEADER32(扩展PE头)结构的最后一个字段为DataDirectory。该字段定义了PE文件中出现的所有不同类型的数据目录信息。如前所述,应用程序中的数据被按照用途分成很多种类,如导出表,导入表,资源,重定位表等。在内存中,这些数据被操作系统以页为单位组织起来,并赋予不同的访问属性;在文件中,这些数据同样被组织起来,按照不同分类分别存放在文件的指定位置。
从Windows NT3.1操作系统开始到现在,该数据目录中定义的数据类型一直是16种。PE中使用了一种称作“数据目录项IMAGE_DATA_DIRCTORY”的数据结构来定义每种数据。该结构只有两个字段,结构具体定义如下:
IMAGE_DATA_DIRCTORY STRUCT
VirtualAddress DWORD ? ;0000h - 数据的起始RVA
isize DWORD ? ;0004h - 数据块长度
IMAGE_DATA_DIRECTORY ENDS
两个字段依次为VirtualAddress和isize,总的数据目录一共由16个相同的IMAGE_DATA_DIRECTORY结构连续排列在一起组成。
这16个元祖的数组每一项均代表PE中的某一类型数据,各数据类型如下:
--------------------------------------------------------------------------------
数组编号 英文描述 中文描述
---------------------------------------------------------------------------------
0 Export table address and size 导出表地址和大小
1 Import table address and size 导入表地址和大小
2 Resource table address and size 资源表地址和大小
3 Exception table address and size 异常表地址和大小
4 Certificate table address and size 属性证书数据地址和大小
5 Base relocation table address and size 基地址重定位表地址和大小
6 Debugging information starting address and size 调试信息地址和大小
7 Architecture-specific data 预留为0
8 Global pointer register relative virtual address 指向全局指针寄存器的值
9 Thread local storage table address and size 线程局部存储地址和大小
10 Local configuration table address and size 加载配置表地址和大小
11 Bound import table address and size 绑定导入表和地址
12 Import address table address and size 导入函数表地址和大小
13 Delay import descriptor address and size 延迟导入表地址和大小
14 CLR Runtime Header address and size CLR运行时头部数据地址和大小
15 Reserved 系统保留
----------------------------------------------------------------------------------
如果想在PE文件中寻找特定类型的数据,就需要从该结构开始。
节表项IMAGE_SECTION_HEADER
PE头IMAGE_NT_HEADERS后紧跟着节表。它由许多个节表项(IMAGE_SECTION_HEADER)组成,每个节表项纪录了PE中与某个特定的节有关的信息。节表中节的数量由字段IMAGE_FILE_HEADER.NumberOfSection来定义。节表项的数据结构详细定义如下:
IMAGE_SECTION_HEADER STRUCT
Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?) ;0000h - 8个字节节名
union Misc
PhysicalAddress dd ?
VirtualSize dd ? ;0008h - 节区尺寸
ends
VirtualAddress dd ? ;000ch - 节区的RVA地址
SizeOfRawData dd ? ;0010h - 在文件中对齐后的尺寸
PointerToRawData dd ? ;0014h - 在文件中的偏移
PointerToRelocations dd ? ;0018h - 在OBJ文件中使用
PointerToLinenumbers dd ? ;001ch - 行号表的位置(调试使用)
NumberOfRelocation dd ? ;002ch - 在OBJ文件使用
Characteristics dd ? ;0024h - 节的属性
IMAGE_SECTION_HEADER ENDS
节表后面就是节的内容,至此本文结束。