17.1.4  节表和节

从排列位置来看,PE文件在DOS部分和PE文件头部分以后就是节表和多个不同的节(如图17.1中的③和④所示)。要理解什么是节表,什么是节以及它们之间的关系,那就首先要了解Windows是如何将PE文件映射到内存的。

1. PE文件到内存的映射

在执行一个PE文件的时候,Windows并不在一开始就将整个文件读入内存,而是采用与内存 映射文件类似的机制,也就是说,Windows装载器在装载的时候仅仅建立好虚拟地址和PE文件之间的映射关系,只有真正执行到某个内存页中的指令或者访 问某一页中的数据时,这个页面才会被从磁盘提交到物理内存,这种机制使文件装入的速度和文件大小没有太大的关系。

图17.2  PE文件到内存的映射

但是系统装载可执行文件的方法又不完全等同于内存映射文件。当使用内存映射文件时,系统对“原 著”非常忠实,如果将磁盘文件和内存映像对比一下,可以发现不管是数据本身还是数据之间的相对位置都是完全相同的。而装载可执行文件的时候,有些数据在装 入前会被预先处理(如需要重定位的代码),而装入以后,数据之间的相对位置也可能改变,如图17.2所示,一个节的偏移和大小在装入内存前后可能是完全不 同的。

Windows装载器在装载DOS部分、PE文件头部分和节表部分时不进行任何处理,而装载节的时候将根据节的属性做不同的处理,一般需要处理以下几个方面的内容。

●   内存页的属性

对于磁盘映射文件来说,所有的页都是按照磁盘映射文件函数指定的属性设置的,但是装载可执行文件时,与节对应的内存页的属性要按照节的属性来设置。所以在同属一个模块的内存页中,从不同节映射过来的内存页的属性是不同的。

●   节的偏移地址

节的起始地址在磁盘文件中是按照IMAGE_OPTIONAL_HEADER32结构的 FileAlignment字段的值对齐的,而被装载到内存中时是按照同一结构中的SectionAlignment字段的值对齐的,两者的值可能不同, 所以一个节被装入内存后相对于文件头的偏移和在磁盘文件中的偏移可能是不同的。

节是相同属性数据的组合,当节被装入到内存中的时候,同一个节对应的内存页将被赋予相同的页属 性,Windows系统对内存属性的设置是以页为单位来进行的,所以节在内存中的对齐单位必须至少是一个页的大小,对于Win32来说,这个值是4 Kb(1000h),而对于Win64来说,这个值是8 Kb(2000h)。

节在磁盘文件中的对齐单位就没有最小4 Kb的限制,为了减少磁盘文件的大小,文件对齐的单位一般要小于内存对齐的单位(FileAlignment的值一般为200h),这样,在磁盘中就不必为每个节最后的零头数据补足4 Kb的大小了。

●   节的尺寸

对节尺寸的处理有两个方面,首先是由于磁盘映像和内存映像中节对齐单位的不同而造成的长度扩展;其次是对包含未初始化数据的节的处理(如图17.2中的.data节)。

对于未初始化数据来说(比如在源代码中定义的.data?段),没必要为它们在磁盘文件中预留空间,只要在可执行文件被装载到内存中后为它们分配空间就可以了,所以包含未初始化数据的节在磁盘文件中的长度被定义为0,但是被装载到内存中的地址和大小是被明确指定的。

对于这种节来说,它所包含的内存页并没有磁盘文件内容与之对应,这些内存页是Windows装载器根据节的定义额外开辟出来的。

●   不进行映射的节

有些节中包含的数据仅仅在装载的时候用到,当文件装载完毕的时候,它们不会被递交到物理内存 页。最典型的例子就是包含重定位数据的节(如图17.2中的.reloc节),重定位数据对于文件的执行代码来说是透明的,它只供Windows装载器使 用,执行代码根本不会去访问它们,一旦装载完毕,继续为它们提交内存页是一种浪费。所以这些节存在于磁盘文件中,但并不会被映射到内存中。

2. 节表

PE文件中所有节的属性都被定义在节表中,节表由一系列的 IMAGE_SECTION_HEADER结构排列而成,每个结构用来描述一个节,结构的排列顺序和它们描述的节在文件中的排列顺序是一致的。全部有效结 构的最后以一个空的IMAGE_SECTION_HEADER结构作为结束,所以节表中总的IMAGE_SECTION_HEADER结构数量等于节的数 量加一。节表总是被存放在紧接在PE文件头的地方,也就是从PE文件头(注意:不是文件本身的头部)开始的偏移为00f8h的地方。

IMAGE_SECTION_HEADER结构的定义如下:

IMAGE_SECTION_HEADER STRUCT

Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?)  ;8个字节的节区名称

union Misc

PhysicalAddress dd    ?

VirtualSize dd        ?               ;节区的尺寸

ends

VirtualAddress dd         ?               ;节区的RVA地址

SizeOfRawData dd          ?               ;在文件中对齐后的尺寸

PointerToRawData dd     ?               ;在文件中的偏移

PointerToRelocations dd ?               ;在OBJ文件中使用

PointerToLinenumbers dd ?               ;行号表的位置(供调试用)

NumberOfRelocations dw  ?               ;在OBJ文件中使用

NumberOfLinenumbers dw  ?               ;行号表中行号的数量

Characteristics dd        ?               ;节的属性

IMAGE_SECTION_HEADER ENDS

结构中的有些字段是供COFF格式的obj文件使用的,对可执行文件来说不代表任何意义,在分析的时候可以不予理会,真正有用的几个字段说明如下。

●   Name1字段

这个字段的字段名原来应该是“Name”,但是这个名称和MASM中的关键字冲突,所以在定义的时候改为“Name1”,Name1字段定义了节的名称,字段的长度为8个字节。

PE文件中的节的名称是一个由ANSI字符组成的字符串,但并没有规定以0结束,如果节的名称字符串长度小于8个字节的话,后面以0补齐,但是字符串长度达到8个字节的话,后面就没有0字符了,所以在处理的时候要注意字符串的结束方式。

每个节的名称是惟一的,不能有同名的两个节,但是节的名称不代表任何含义,它仅仅是为了查看方便而设置的一个标记而已,可以选择任何名称甚至将它空着也可以,将包含代码的节命名为“DATA”或者将包含数据的节命名为“CODE”都是合法的。

各种编译器都以自己的方式对节进行命名,所以,在PE文件中可以看到各式各样的节名称,比如,在MASM32产生的可执行文件中,代码节被命名为“.text”;可读写的数据节被命名为“.data”;包含只读数据、导入表以及导出表的节被命名为“.rdata”;而资源节被命名为“.rsrc”等。但是在其他一些编译器中,导入表被单独放在“.idata”中;而代码节可能被命名为“.code”。

当从PE文件中读取需要的节时,不能以节的名称作为定位标准,正确的方法是按照IMAGE_OPTIONAL_HEADER32结构中的数据目录字段定位。

笔者曾看过一篇介绍如何存取PE文件资源的文章,其中用查找“.rsrc”节的方法得到资源,虽然大部分情况下用这种方法也可以正确地找到资源,但是严格地讲,只有数据目录的IMAGE_DIRECTORY_ENTRY_RESOURCE项才永远正确地指向资源数据。

●   VirtualSize字段

代表节的大小,这是节的数据在没有进行对齐处理前的实际大小。

●   VirtualAddress字段

指出节被装载到内存中后的偏移地址,这是一个RVA地址。这个地址是按照内存页对齐的,它的数值总是SectionAlignment的值的整数倍。

●   PointerToRawData字段

指出节在磁盘文件中的所处的位置。这个数值是从文件头开始算起的偏移量。

●   SizeOfRawData字段

指出节在磁盘文件中所占的空间大小,这个数值等于VirtualSize字段的值按照FileAlignment的值对齐以后的大小。

依靠这4个字段的值,装载器就可以从PE文件中找出某个节(从 PointerToRawData偏移开始的SizeOfRawData字节)的数据,并将它映射到内存中去(映射到从模块基地址开始偏移 VirtualAddress的地方,并占用以VirtualSize的值按照页的尺寸对齐后的空间大小)。

●   Characteristics字段

这是节的属性标志字段,其中的不同数据位代表了不同的属性,具体的定义如表17.5所示,这些数据位组合起来描述了节的属性。

表17.5  节的属性标志位含义

数据位在Windows.inc中的预定义值以及为1时的含义

5

(IMAGE_SCN_CNT_CODE或00000020h)节中包含代码

6

(IMAGE_SCN_CNT_INITIALIZED_DATA或00000040h)节中包含已初始化数据

7

(IMAGE_SCN_CNT_UNINITIALIZED_DATA或00000080h)节中包含未初始化数据

25

(IMAGE_SCN_MEM_DISCARDABLE或02000000h)节中的数据在进程开始以后将被丢弃,前面举例的包含重定位表的.reloc节就是一个例子

26

(IMAGE_SCN_MEM_NOT_CACHED或04000000h)节中的数据不会经过缓存

27

(IMAGE_SCN_MEM_NOT_PAGED或08000000h)节中的数据不会被交换到磁盘

28

(IMAGE_SCN_MEM_SHARED或10000000h)表示节中的数据将被不同的进程所共享,在第11章的钩子例子中的共享数据的节就设置了这个属性标志

29

(IMAGE_SCN_MEM_EXECUTE或20000000h)映射到内存后的页面包含可执行属性

30

(IMAGE_SCN_MEM_READ或40000000h)映射到内存后的页面包含可读属性

31

(IMAGE_SCN_MEM_WRITE或80000000h)映射到内存后的页面包含可写属性

代码节的属性一般为60000020h,也就是可执行、可读和“节中包含代码”;数据节的属性 一般为c0000040h,也就是可读、可写和“包含已初始化数据”;而常量节(对应源代码中的.const段)的属性为40000040h,也就是可读 和“包含已初始化数据”;资源节的属性和常量节的属性一般是相同的。

当然节属性的定义不一定就是这些值,比如,当PE文件被压缩工具压缩以后,包含代码的节往往被 同时设置了可执行、可读和可写属性,因为解压部分需要将解压后的代码回写到代码段中。读者可以做个实验:在程序中往代码段写数据,编译链接完成后执行一下 肯定会引发异常,然而用Upx等压缩软件压缩后再执行,就会发现文件可以正常执行了,这就是因为压缩软件为了解压的需要而将节的属性设置为可写了。

 
 
 

PE文件格式---节和节表的更多相关文章

  1. PE文件格式详解,第三讲,可选头文件格式,以及节表

    PE文件格式详解,第三讲,可选头文件格式,以及节表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶可选头结构以及作 ...

  2. 小甲鱼PE详解之区块表(节表)和区块(节)(PE详解04)

    到此为止,小甲鱼和大家已经学了许多关于 DOS header 和 PE header 的知识.接下来就该轮到SectionTable (区块表,也成节表).(视频教程:http://fishc.com ...

  3. 在PE中,新增节,添加代码

    在PE中,新增节,添加代码 一.先判断节表后是否有空闲位置,添加节表信息,必须多出两个节表位置,最后以零结尾. 二.新增节后,需要修改以下信息 1.添加一个新节,可以复制一份,最好是拥有可执行属性的节 ...

  4. Laravel小项目之第4节 Laravel-通过表单实现新增及操作状态提示功能

    第4节 Laravel-通过表单实现新增及操作状态提示功能 4.1 显示新增表单视图 4.2 通过模型实现新增 4.3 操作状态提示 4.1 显示新增表单视图 修改边栏的链接 \resources\v ...

  5. Reverse Core 第二部分 - 13章 - PE文件格式

    @date: 2016/11/24 @author: dlive ​ PE (portable executable) ,它是微软在Unix平台的COFF(Common Object File For ...

  6. 深入理解 Win32 PE 文件格式

    深入理解 Win32 PE 文件格式 Matt Pietrek 这篇文章假定你熟悉C++和Win32. 概述 理解可移植可执行文件格式(PE)可以更好地了解操作系统.如果你知道DLL和EXE中都有些什 ...

  7. PE文件格式详解,第二讲,NT头文件格式,以及文件头格式

    PE文件格式详解,第二讲,NT头文件格式,以及文件头格式 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) PS:本篇博客 ...

  8. PE文件格式分析

    PE文件格式分析 PE 的意思是 Portable Executable(可移植的执行体).它是 Win32环境自身所带的执行文件格式.它的一些特性继承自Unix的Coff(common object ...

  9. PE文件格式介绍

    Useful Tools: 1. WDK安装目录下搜下depends.exe,这个工具可以查看.exe文件依赖的.dll,以及用到的dll中的api. 2.PE文件格式分析器: 有很多的PE格式分析器 ...

随机推荐

  1. 在生产环境下实现每天自动备份mysql数据库

    1.描述 我相信很多朋友在工作都都会有这种需求,老板或领导让你每天都要备份mysql数据库,你该如何实现呢,是每天到一定的时间在服务器上敲一遍mysql的备份命令,还是想写个脚本,定时定点的自动备份呢 ...

  2. Python While循环、运算符以及一些基础运用

    1.循环语句 循环打印"人生苦短,我用python" while True: print("人生苦短,我用python") 利用While循环,打印1~10 c ...

  3. android 极光推送 声音与振动 的关闭和开启

    前言:最近刚好在写一些推送方面的东西,又是新手,不断在网上找资料,很少,不过还是找到了一些,反正百度我是再也不想百度了,谷歌一下子就能找到想要的. 废话不多说. 1.主要方法就是如下一个函数 priv ...

  4. this.$router 和this.$route 的区别

    1. this.$router: 表示全局路由器对象,项目中通过router路由参数注入路由之后,在任何一个页面都可以通过此方法获取到路由器对象,并调用其push(), go()等方法: 2. thi ...

  5. 10 RESTful 实现权限控制

    1 2 身份控制 3 4 只能显示5条数据 5 权限控制 序列化渲染深度 6

  6. 微服务化的不同阶段 Kubernetes 的不同玩法

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 作为容器集群管理技术竞争的大赢家,Kubernetes已经和微服务紧密联系,采用Kubernetes的企业往往都开始了微服务架构的探索.然而不同企业 ...

  7. Singleton模式类 【微软面试100题 第七十二题】

    题目要求: 实现C++单例模式,即只能生成一个实例的类. 题目分析: 1.一般情况:用构造函数私有化和静态函数实现. 2.如果考虑内存泄露:用智能指针+一般情况方法. 3.如果考虑线程安全:加锁. 代 ...

  8. C#入门篇6-3:字符串操作 string的ToString() Split()和Copy()方法

    //ToString()方法 public static void OutPut() { //字符型转换 转为字符串 Console.WriteLine(.ToString("n" ...

  9. Vue声明渲染以及axios实例

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  10. RSA进阶之维纳攻击(wiener-attack )

    维纳攻击: 场景:e很大 例题: 第七届山东网络安全技能大赛 链接:https://pan.baidu.com/s/1IRInw3pB7SQfp3MxRJW17A 提取码:lcn3 e很大,妥了,维纳 ...