当前位置: 首页 > news >正文

第3章 Windows运行机理-3.5 PE结构分析(1)

3.5.2 表节

PE文件的真正内容划分成块,称之为sections(节)。每节是一块拥有共同属性的数据,比如代码/数据、读/写、导入/导出等。我们可以把PE文件想像成一逻辑磁盘,PE header 是磁盘的boot扇区,而sections就是各种文件,每种文件自然就有不同属性,如只读、系统、隐藏、文档等。节的划分是基于各组数据的共同属性,而不是逻辑概念。重要的不是数据/代码是如何使用的,如果PE文件中的数据/代码拥有相同属性,它们就能被归入同一节中。

不必关心节中类似于“data”、“code”或其他的逻辑概念:如果数据和代码拥有相同属性,它们就可以被归入同一个节中。节名称仅仅是个区别不同节的符号而已,自己也可以定义一些不同的名字的字。

节表位于PE头标和映像节的生数据中间,节表包含了关于映像中的每节的信息。映像的节是以它们的地址而不是其字母来排序的。

在此处是值得弄清楚一个节到底是什么的时候了。

然而与NE文件的段表又不同,一个PE节表并不为每个代码或数据块保存一个选择器的值。取而代之的是,节表的每一项存储一个地址,该地址是文件的生数据被影射入内存所在位置的地址。尽管节类似于32位段,但它们确实不是单独的段。实际上,一个节简单地对应一个进程的虚拟地址空间中的一片内存区域。

PE文件不同于NE文件的另一个方面,体现在它们是如何管理支撑数据方面,你的应用程序不使用这些支撑数据,但操作系统要用。可执行模块用到的DLL列表和安置表的位置是支撑数据的两个例子。

用PE文件就不同了。任何被认为是相关的代码和数据被存储在一个节中。因此,关于引入函数的信息存储在它自己的节中,它被作为模块引出的函数表。对重定位数据也是如此。任何可能被程序或操作系统需要的代码或数据同样也是获得它们自己的节。

我先描述操作系统管理这些节所用的数据,在内存中,紧跟在PE头标之后的是一个IMAGE_SECTION_HEADER数组。这个数组中的元素个数在PE头标中(的IMAGE_NT_HEADER.FileHeader.NumberOfSection域)给出。

IMAGE_SECTION_HEADER的结构如下:

typedef struct _IMAGE_SECTION_HEADER {

BYTE Name[IMAGE_SIZEOF_SHORT_NAME];

union {

DWORD PhysicalAddress;

DWORD VirtualSize;

} Misc;

DWORD VirtualAddress;

DWORD SizeOfRawData;

DWORD PointerToRawData;

DWORD PointerToRelocations;

DWORD PointerToLinenumbers;

WORD NumberOfRelocations;

WORD NumberOfLinenumbers;

DWORD Characteristics;

} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

用PEDUMP程序可输出节表和所有节的域和属性。下面分别显示了一个典型的EXE文件PEDUMP输出的节表以及一个OBJ文件的节表输出。

Section Table

01 .text VirtSize: 00002C2A VirtAddr: 00001000

raw data offs: 00000400 raw data size: 00002E00

relocation offs: 00000000 relocations: 00000000

line # offs: 00000000 line #'s: 00000000

characteristics: 60000020

CODE MEM_EXECUTE MEM_READ

02 .rdata VirtSize: 0000038F VirtAddr: 00004000

raw data offs: 00003200 raw data size: 00000400

relocation offs: 00000000 relocations: 00000000

line # offs: 00000000 line #'s: 00000000

characteristics: 40000040

INITIALIZED_DATA MEM_READ

03 .data VirtSize: 00001334 VirtAddr: 00005000

raw data offs: 00003600 raw data size: 00001000

relocation offs: 00000000 relocations: 00000000

line # offs: 00000000 line #'s: 00000000

characteristics: C0000040

INITIALIZED_DATA MEM_READ MEM_WRITE

04 .idata VirtSize: 000006E2 VirtAddr: 00007000

raw data offs: 00004600 raw data size: 00000800

relocation offs: 00000000 relocations: 00000000

line # offs: 00000000 line #'s: 00000000

characteristics: C0000040

INITIALIZED_DATA MEM_READ MEM_WRITE

05 .rsrc VirtSize: 00000550 VirtAddr: 00008000

raw data offs: 00004E00 raw data size: 00000600

relocation offs: 00000000 relocations: 00000000

line # offs: 00000000 line #'s: 00000000

characteristics: 40000040

INITIALIZED_DATA MEM_READ

06 .reloc VirtSize: 0000041E VirtAddr: 00009000

raw data offs: 00005400 raw data size: 00000600

relocation offs: 00000000 relocations: 00000000

line # offs: 00000000 line #'s: 00000000

characteristics: 42000040

INITIALIZED_DATA MEM_DISCARDABLE MEM_READ

每个IMAGE_SECTION_HEADER是关于EXE或OBJ文件中一节信息的一个完整数据库,它具有如下格式。

Name[IMAGE_SIZEOF_SHORT_NAME]:这是给本节命名的一个8字节长的ANSI名,多数节名以一个小数点作为开始(例如:.text),你也可以在微软C/C++编译器中用#pragma data_seg和#pragma code_seg来命名。重要的是,注意如果节名占满了8个字节,则没有NULL中止字节。如果你爱用printf(),可使用“%.8s”,以避免拷贝名字串到另一缓冲区时误用空白符中止了它。

Misc:根据是出现在EXE文件中还是在OBJ文件中,该域具有不同的含义。在一个EXE中,它保存代码或数据节的虚拟尺寸,这是调整到最接近文件对齐值倍数的尺寸,本结构中后面的SizeOfRawData域保存这个对齐值。对于OBJ文件,该域指示本节的物理地址。第一节在地址0上开始。要找到其下一节的物理地址,只需要将SizeOfRawData值与当前的此物理地址相加即可。

VirtualAddress节:的RVA(相对虚拟地址)。PE装载器将节映射至内存时会读取本值,因此如果域值是1000h,而PE文件装在地址400000h处,那么本节就被载到401000h。

SizeOfRawData:在EXE文件中,该域含本节被对齐到文件对齐尺寸后的尺寸。

PointerToRawData:这是基于文件的偏移量,用它可以找到本节的生数据所在位置。如果你自己内存映射一个PE或COFF文件(而不是让操作系统装载它),则该域比VirtualAddress更为重要。那是因为在这种情况下,你将有整个文件的一个完全线性映射,因此你将在该偏移处找到本节的数据,而不是用VirtualAddress域指定的RVA。

PointerToRelocations:在OBJ文件中,这是一个该节重定位信息基于文件的偏移量。OBJ每节的重定位信息直接跟在该节数据之后。在EXE文件中,这个域(和后一个域)无意义,并总被置为0。当连接器创建EXE时,它已解决了大多数的地址分配和安排问题,只有基地址重定位和引入函数才在装载时解决。有关基地址和引入函数的信息存储在基地址和引入函数节中。因此,对一个EXE,不需要在节的生数据之后还要有每节重定位的数据。

http://www.jsqmd.com/news/429086/

相关文章:

  • 人工智能+的七大赛道
  • 【医学数据分析与挖掘】(一):概述
  • 【node】Prisma 基础使用
  • python+flask+vue框架的个人健康菜谱生成系统_ 项目源码
  • 【python】使用chinesecalendar判断是不是工作日
  • python+flask+vue框架的个人物品管理系统
  • 大模型开发全景图升级:7大框架+3平台+7UI,助你抢占AI高地!
  • 普通人怎么学AI
  • Hadoop集群搭建实战:手把手教你部署高可用环境
  • 7.5kw异步电机经典矢量控制仿真:Matlab/Simulink 实战
  • 告别知识孤岛!Wiki.js打造知识库,并实现随处可用。
  • Virtio 虚拟化 I/O 框架:间接描述符与 Event Index
  • python+flask+vue框架的基于.的社区服务平台 项目源码
  • python+flask+vue框架的基于 的图书借阅管理信息系统
  • Planner to PowerBI
  • 提示工程人才培养的敏捷学习路径:快速响应业务需求
  • 【2026年最新600套毕设项目分享】基于SpringBoot的智慧医疗问诊系统(14030)
  • Blender 基础操作
  • Bambu Studio基本操作
  • 企业数字空间设计的100个知识点:AI应用架构师的精华总结
  • AI应用架构师必学:伦理框架从理论到实践的案例拆解
  • AI如何影响各行各业,各行各业如何拥抱AI
  • 大数据领域Kafka的性能优化策略总结
  • 智慧工地防护服佩戴识别 安全帽图像识别 反光衣穿戴识别 工地安全监控 工地安全监测 人员防护装备合规性检查 智能安防监控第10511期 +deepseek
  • HBase与Hive整合:SQL查询大数据存储
  • 增强AI模型探索能力的策略设计
  • Windows 10/11 !暂时! 解决CMD命令行下中文乱码问题
  • 杀疯了!这些 C++ JS 冷门骚操作,每一行都堪称「语法黑魔法」
  • 蓝桥/16/B.1/可分解的正整数
  • AI 发展史