PE学习(7) 合并为一个节

合并为一个节的目的是缩小节表的大小,以在节表剩余空间不足时完成新增节的操作

整体思路:

实际上可以不进行拉伸,直接在FileBuffer层面进行操作,但本文还是按照海哥要求来做

继续摆上老图

 

准备工作

通过之前文章的代码,先将FileBuffer转为ImageBuffer

和之前的文章一样,对ImageBuffer进行头部的解析

拿到节表中的最后一节的指针

计算内存中的SizeOfHeaders的对齐值,这个值的意义是后续计算finalSectionsSize

如果这里不按照SectionAlignment对齐,那么拿不到第一节之前的头部总大小,因为只能在PE头里拿到FileBufferSizeOfHeaders,这个值在拉伸对齐后会变化

比较 内存中最后一节对齐前大小VirtualSize 和 文件中对齐后大小SizeOfRawData

计算得到最后一节在内存中的真正大小,虽然图片中看起来Misc.VirtualSize小于SizeOfRawData,但某些节的Misc.VirtualSize包含了未初始化的变量,所以VirtualSize有可能会更大

找到两者中更大的一个值,作为最后一节的有效内存大小,下一步计算新节的有效大小

finalSectionsSize变量记录了从内存中第一节到最后一节的有效内存之前的总大小

 

处理节表

遍历节表,通过|操作将所有节表拥有的属性记录到NewSecCharacteristics确保新的合并节拥有以前所有节的属性,以防止出现意外的情况。另外仅保留第一个节表的内容,从第二个节表开始,全部设置为0

将第一个节表的内存对齐前大小和SizeOfRawData设为所有节一共的大小,设置第一个节属性Characteristics为所有节共有的属性,修改节数量为1

 

分配内存

分配内存,初始化为0,并复制头部

已经计算并设置了大节表的SizeOfRawData,从内存中第一个VirtualAddress偏移开始,按照大节表的SizeOfRawData复制,一次复制就可以将所有节内容复制过去

接下来可以直接把pTempMergeSection写入新EXE

 

一些思考

可以看到,这里把原来内存中的所有节信息固定了,导致最终写入的新EXE变大了不少。合并节的意思是合并节表,但不能压缩节的内容,内存中的偏移是不能动的,否则将无法执行

因此合并成一个节后,需要把拉伸后的所有节的字节拿过来,当成现有唯一节的有效字节

但存在的疑问是,计算出的finalSectionsSize忽略了原来最后一节的对齐部分,这个问题在分配新内存时使用了原有的SizeOfImage大小,这个大小是完整的节大小,可以弥补忽略的部分

最后的问题是,复制的字节从PointerToRawData偏移开始写入完整的节,但是定义了总大小为SizeOfImage,这样导致了末尾可能会多出了一部分垃圾数据

对合并前后的EXE进行对比,发现末尾确实多出了一堆0