第13章:PE文件格式(1)

一年前看过一次,但没有实实在在的理解,这次争取结合实际的PE文件再看看.

 

一般来说,很多文件为了提高使用率,都会使用一个"最小基本单位"的概念.PE文件中各节区的起始位置在某个最小单位的倍数上.

若不够,则空白区域用NULL填充.

 从硬盘加载到内存中,会从相对虚拟地址(RVA)变化为虚拟地址(VA).当然随着所处位置的不同,其最小基本单位也会发生变化,导致NULL填充区变大.

PE 头

DOS头

首先前四十字节是一个IMAGE_DOS_HEADER的结构体--DOS头:

 结构体包含如下几个字段:

 注意:WORD占两字节,DWORD占四字节

 e_magic是DOS签名,该结构体的最后一个字段e_lfanew是NT头的偏移,此处偏移值是e0.

紧跟着的是DOS存根(stub),是一个可选项.由代码和数据混合而成,大小不确定.此处40-4D处是代码,int 21执行时由

eax寄存器中的值来决定执行哪个中断.此处debug模式下,将数据(This ...)识别为了代码.故40-7F为DOS存根段.

 

 若使用得当,可以在DOS存根处写入代码,使得在DOS模式下运行16位程序,在Windows下运行32/64位程序.

对DOS头,DOS存根做一个总结:

1.DOS存根是可选的,大小变化的,可以在里面写入汇编程序以运行在16位DOS模式下.

2.DOS头是固定的40字节.

3.DOS头第一个是DOS签名--MZ,最后一个是e_lfanew,是NT头的偏移(从地址0开始),因为DOS存根大小不确定.

NT头

即IMAGE_NT_HEADERS.有三个成员:PE,文件头(File Header)可选头(Optional Header).

 识别出来并不困难,找到PE即可.

接下来是文件头结构体(黑色划线部分),重要的有如下几个

首先是机器码(Machine),此处位014C,表明是intel 386的CPU

第二个是节区数(NumberOfSections),此处为3.

第三个是可选头大小(SizeOfOptionalHeader),用来指出IMAGE_OPTIONAL_HEADER32/64的长度,此处是e0

第四个是Characteristics,用来标识文件属性此处是10f,即包含了重定向信息删除,可执行文件,行数移除,本地符号表移除以及系统文件等属性

 可选头(Image_Optional_Header)PE结构体最大的.

 

1#.Magic 

可选头是32结构体时位,该值为10B;可选头是64位结构体时,该值为20B.

2#.AddressOfEntryPoint

标识处EP的RVA值,指出程序最先执行的代码起始地址.动态反汇编软件会从其中读取出值.

3#.ImageBase

指出PE文件优先装入的地址.EXE,DLL被装载到0~FFFFFFFF(32位系统),SYS文件被装载到80000000~FFFFFFFF.一般来说,EXE的基址是00400000,DLL的基址位10000000.执行PE文件时,PE转载器先创建进程,再将文件载入内存,最后EIP=ImageBase+AddressOfEntryPoint.

4#.SectionAlignment,FileAlignment

SectionAlignment指定了节区在磁盘文件中的最小单位,FileAlignment指定了节区在内存中的最小单位.

5#.SizeOfImage

PE文件在虚拟内存中所占空间的大小.

6#.SizeOfHeaders

指出PE头的大小.

7#.Subsystem

区分系统文件与普通的可执行文件.

8#.NumberOfRvaAndSizes

指定最后一个成员DataDirectory数组的个数,以这个为准,而不是IMAGE_NUMBEROF_Directory_Entries(16)

9#.DataDirectory

 非常重要的是Export / Import  / Resource Directory,TLS Direction.

对NT头做一个总结:

1.NT头包含三个元素:PE,File Header,Optional Header.

2.文件头中的第一个元素是机器码,I386的CPU是0x014C,倒数第二个是可选头大小,32/64位系统的可选头大小不同,最后一个是文件属性,0x2是exe,0x20000是DLL

3.从PE开始,数18H字节就到了可选头的第一个元素.

4.DataDirectory[n]结构体中的每一个都有两个属性:一个是相对虚拟地址,一个是大小.其中每个结构体的大小为8字节

节区头

 即IMAGE_SECTION_HEADER结构体.它定义了每个节区的相关信息.

重要的元素有下面几个:

1#.VirtualSize

指示内存中节区所占的实际大小,通常这个值会被对齐到某个整数.

2#.VirtualAddress

内存中节区的起始地址.其实是相对虚拟地址,通常会加上一个ImageBase值.通常第一个节区的值会被置为1000H.会按照SectionAlignmnet的值对齐.

3#SizeOfRawData

磁盘文件中节区所占的大小.这个值通常是对VirtualSize依照FileAlignment的值进行对齐后所得到的.

4#.PointerToRawData

指示该节区在文件中的起始位置.已按照FileAlignment对齐.

5#.Characteristics

文件属性.由bits组合而成.

猜你喜欢

转载自www.cnblogs.com/Rev-omi/p/13170124.html