紧跟在PE Header后面的Section Table(节表)

节表:其实是一个IMAGE_SECTION_HEADERS数组。单个节表的数据大小为40

IMAGE_NT_HEADERS.FileHeader.NumberOfSections指出。
IMAGE_SECTION_HEADERS结构
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

 这里可以得出区块的大小:

 

FieldMeanings
Name1 事实上本域的名称是"name",只是"name"已被MASM用作关键字,所以我们只能用"Name1"代替。这儿的节名长不超过8字节。记住节名仅仅是个标记而已,我们选择任何名字甚至空着也行,注意这里不用null结束。命名不是一个ASCIIZ字符串,所以不用null结尾。
VirtualAddress 本节的RVA(相对虚拟地址)。PE装载器将节映射至内存时会读取本值,因此如果域值是1000h,而PE文件装在地址400000h处,那么本节就被载到401000h
SizeOfRawData 经过文件对齐处理后节尺寸,PE装载器提取本域值了解需映射入内存的节字节数。(译者注: 假设一个文件的文件对齐尺寸是0x200,如果前面的 VirtualSize域指示本节长度是0x388字节,则本域值为0x400,表示本节是0x400字节长)。
PointerToRawData 这是节基于文件的偏移量,PE装载器通过本域值找到节数据在文件中的位置。
Characteristics 包含标记以指示节属性,比如节是否含有可执行代码、初始化数据、未初始数据,是否可写、可读等。

现在我们已知晓 IMAGE_SECTION_HEADER结构,再来模拟一下 PE装载器的工作吧:

  1. 读取 IMAGE_FILE_HEADERNumberOfSections域,知道文件的节数目。
  2. SizeOfHeaders域值作为节表的文件偏移量,并以此定位节表。(节表的偏移量=所有头的总和-节数*节表长度=SizeOfHeaders的值-(NumberOfSections*单个节表的长度40))
  3. 遍历整个结构数组检查各成员值。
  4. 对于每个结构,我们读取PointerToRawData值并定位到该文件偏移量。然后再读取SizeOfRawData域值来决定映射内存的字节数。将VirtualAddress域值加上ImageBase域值等于节起始的虚拟地址。然后就准备把节映射进内存,并根Characteristics域值设置属性。
  5. 遍历整个数组,直至所有节都已处理完毕。
原文地址:https://www.cnblogs.com/wang-can/p/3280429.html