区块/节表

紧跟IMAGE_NT_HEADERS的是区块表,它是一个IMAGE_SECTION_HEADER结构数组。该数组的数目由 IMAGE_NT_HEADERS.FileHeader.NumberOfSections指出。第一个节表的位置为Optional_Header位置+SizeOfOptionalHeader

typedef struct _IMAGE_SECTION_HEADER {
BYTE  Name[IMAGE_SIZEOF_SHORT_NAME];        // 块名
union {
  DWORD PhysicalAddress;                    // 物理地址
  DWORD VirtualSize;                        // 指出实际被使用的区块的大小
} Misc;
DWORD VirtualAddress;                       // 该块装载到内存中的RVA
DWORD SizeOfRawData;                        // 该块在磁盘中所占的空间
DWORD PointerToRawData;                     // 该块在磁盘文件中的偏移
DWORD PointerToRelocations;                
DWORD PointerToLinenumbers;
WORD  NumberOfRelocations;
WORD  NumberOfLinenumbers;
DWORD Characteristics;                      // 块属性
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

Name:8个字节 一般情况下是以"\0"结尾的ASCII吗字符串来标识的名称,内容可以自定义.并且无论是不是以‘/0’结束,系统都只截取8个字节。
Misc:双字,是该节在没有对齐前的真实尺寸,该值可以不准确。
VirtualAddress:节区在内存中的偏移地址。加上ImageBase才是在内存中的真正地址。
SizeOfRawData:节在文件中对齐后的尺寸。
PointerToRawData:节区在文件中的偏移。
Characteristics:节的属性,包括可读,可写,可执行

节表的数量在标准pe头里面的NumberOfSection

新增节

0x1要新增一个节首先要判断一下SizeoOfHeaders-DOS头-PE标识大小-File头-Optional头-所有节表的大小是否大于两个节表的大小。如果没有足够的空间就要考虑移动NT头和节表。
0x2空间足够开始操作,先找到最后一个节表的位置。新节VirtualAddress=上一个节VirtualAddress+上一个节的SizeOfRawData或者VirtualSize谁大取谁。新节PointerToRawData=上一个节PointerToRawData+上一个节的SizeOfRawData;
0x3新节的SizeOfRawData和SizeOfRawData均为添加节的大小;Name:8位(16字节)的ASCII码,Characteristics:根据自己的需要写。

合并节

0x1拉伸到内存
0x2Max = SizeOfRawData>VirtualSize?SizeOfRawData:VirtualSize
0x3N=最后一个节的VirtualAddress + Max - SizeOfHeaders内存对齐后的大小
0x4第一个节的SizeOfRawData=VirtualSize=N,修改节的属性,使之包含所有节的属性
PS:需要注意的是这里需要把SizeOfHeaders转为内存对齐的大小,海哥之所以让用记事本是因为它的文件对齐和内存对齐不一样,需要转化一下

扩大节

0x1拉伸到内存
0x2分配一块新的空间:SizeOfImage + 需要扩大的大小
0x3 N = (最后一个节SizeOfRawData或者VirtualSize 内存对齐后的值,谁大取谁)+需要扩大的空间
0x4最后一个节SizeOfRawData和VirtualSize=N

Rva和Foa相互转换

0x1通过遍历找到需要转换的地址在哪个节表
0x2Foa=va-所在在节的VirtualAddress+所在节PointerToRawData。Rva=oa-所在在节的PointerToRawData-VirtualAddress

最后修改:2020 年 11 月 02 日
如果觉得我的文章对你有用,请随意赞赏