为了更好的理解PE文件结构,首先得了解增加一个节区需要修改什么,本片博客先去除.reloc节区再增加一个新的.new节区。
- FileHeader.NumberOfSections 节区数量
- OptionalHeaders.SizeOfHeaders PE头的大小(因为增加了一个新的IMAGE_SECION_HEADER)
- OptionalHeaders.SizeOfImage 加载入内存后的PE映像大小
- 构造新的IMAGE_SECTION_HEADER
- 在节区的末尾添加新的内容
这里只使用2个工具PEView和WinHex,等熟悉之后可以使用例如010Editor之类更方便的工具
现在我用VS2019编写一个Hello, World程序,程序代码如下:
#include
#include
int _tmain() {
MessageBox(NULL, "Hello, world!", "Hi", MB_OK);
return(0);
}
获取其32位的Release版本,看一下它的PE结构如下:
可以看到其有5个节区,接下来我们删去重定位节区(.reloc)并自己加入一个.new节区,首先进行.reloc节的删除工作。而删除工作的第一步就是把节区数据给删掉,看下图:
可以看到.reloc节在文件中的偏移是0x2200开始的,由于这是最后一节所以从0x2200开始的所有数据就可以直接清除了。
接下去修改FileHeader.NumberOfSections和OptionalHeader.SizeOfHeader。
NumberOfSections减去一因为我们要去掉一个节区。
NumberOfSection位于0x0FE位置,将其该为4
由于整个PE头部(DOS头+NT头+节区头)大小是0x2B7而SizeOfHeader由于要求磁盘内以0x200为单位进行对齐,而0x2B7>0x200,所以为了保持对齐,取了0x400。我们把0x2B7-0x28(十进制是40) > 0x200,所以我们不需要变化SizeOfHeader。
完成这一步后我们还需要做两件事情,删除IMAGE_SECTION_HEADER并且最终修改SizeOfImage。
找到.reloc节区头的起始位置,并将从0x290开始的40个字节全部清零,如下:
修改SizeOfImage,可以看到载入内存中.reloc的大小是0x1E0,因为在内存中要以SectionAlignment对齐,而SectionAlignment是0x1000,所以要把SizeOfImage减去0x1000:
找到SizeOfImage位于
并修改成0x5000,如下:
最终保存后,顺利运行。
增加新的节区和删除一个节区是一个套路,懂得删去在自己捣鼓捣鼓就能会新增节区了。依旧是前面的Hello程序,首先把零散的东西改掉,比如NumberOfSections,依旧是0xEF的位置:
将其改成5。并且把由于要增加一个新的节区所以SizeOfImage重新增加回0x6000:
同样,由于PE头总大小依旧在0x200-0x400之间,所以不需要进行改变。接着构造新的节区,新的节区需要构造新的节头,从0x290开始的40个字节保留。
构造.new节的表头如下:
VirtualSize我设置成了0x1000即我们增加SizeOfImage的大小,并且是从0x5000处开始,这样正好增加0x1000就是SizeOfImage的大小。而Size Of Raw Data是在文件中偏移0x200的大小,从0x2200开始扩展到0x2400,最后的Characteristics我是根据数据段的来的是0xC0000040。
完成这一步后开始把.new节扩充出来。
最终成功调用:
看一下新的PE结构:
(完)