如何在Windows PE 32位可执行文件中为我的代码洞创造空间

所以我想在minesweeper.exe(典型的Windows XP扫雷游戏,链接: 扫雷 )中为我的代码洞穴腾出空间。 所以我通过CFF资源pipe理器修改了文件的PE头,增加了.text部分的大小。

SEGS

我尝试增加.text段的原始大小1000h(新大小是3B58),但Windows无法find入口点,游戏无法启动。 然后我尝试增加.rsrc部分的大小,添加一个新的部分,增加图像大小,但是这些尝试都没有成功,Windows说“这不是x32可执行文件”。

所以这里是一个问题:我如何为我的代码洞穴腾出空间? 我不想search编译器留下的空白空间,我想为我的代码打印1000h字节。 一个教程,以及如何做到这一点,而不破坏游戏的详细解释将是伟大的! (是的,我其实是黑客扫雷)

您不能增加一个部分的大小,而不会使以下部分失效(通常是因为它使这些部分中的偏移量和地址无效)。 这仍然是可能的,但它是非常容易出错的,当你有一个更简单的解决方案时不值得麻烦。

通常情况下,您需要在PE 的末尾添加一个部分然后从代码部分跳转到此部分。 在代码段(代码洞)的末尾通常会有一些空间,所以你可以把你的JMP(或者一些代码片段)重定向到新的部分。 您也可以添加其他新的部分数据或新的资源或任何你想要的。


注意:我使用两个工具:CFF浏览器作为PE浏览器; 十六进制编辑器。

这个文件非常特别,所以添加一个新的部分比通常要困难一些。

开始吧!

以下是IMAGE_SECTION_HEADER数组的十六进制视图:

部分标题

通常有一些空间来添加一个新的部分,但在这种情况下,没有…最后一节标题紧接着是一些东西。

根据内容判断,这可能是一个绑定的导入目录,这在CFF浏览器(绑定目录的偏移量为0x248)中得到确认:

绑定的导入目录

绑定的导入目录是没有用的,尤其是在ASLR中,所以我们可以将整个目录清零:

归零的绑定导入目录

您也可以将数据目录中的绑定导入目录RVA清零,但这不是严格要求:

在这里输入图像说明

现在是时候添加新的部分了。

添加一个新的部分

扫雷器默认有3个部分,所以将部分的数量从3增加到4:

增加部分的数量

转到部分标题并添加一个新的部分(您可以直接在CFF资源管理器中):

新的部分

你需要选择两个数字:

  • 新节的原始大小(我选了0x400); 它必须FileAlignment (在这种情况下是0x200)。

  • 新部分的虚拟大小(我选择了0x1000); 它必须SectionAlignement的倍数(对于这个二进制数是0x1000)。

现在我们需要计算另外两个成员, Virtual AddressRaw Address

虚拟地址

我们以第一部分和第二部分为例。

第一部分从0x1000开始,具有0x3A56的虚拟大小。 下一节虚拟地址必须SectionAlignement (0x1000)对齐,所以计算是(在这里使用python):

 >>> def round_up_multiple_of(number, multiple): num = number + (multiple - 1) return num - (num % multiple) >>> hex(round_up_multiple_of(0x1000 + 0x3a56, 0x1000)) '0x5000' 

哪个给0x5000哪个是正确的(.data段从0x5000开始)。

现在,我们最后一节应该从哪里开始?

.rsrc部分从0x6000开始,大小为0x19160:

 >>> hex(round_up_multiple_of(0x6000 + 0x19160, 0x1000)) '0x20000' 

所以它必须从0x20000开始。 把这个号码放在Virtual Address

原始地址

(通常这是不需要的,因为所有的部分已经对齐了,最后一部分必须从文件末尾开始,但是我们会这样做)。

我们从一个例子开始(第一和第二部分):

第一部分的原始地址是0x400,原始大小是0x3c00。 FileAlignement是0x200,因此:

 >>> hex(round_up_multiple_of(0x400 + 0x3c00, 0x200)) '0x4000' 

第二部分应该在0x4000的文件(其Raw address )上开始,这是正确的。

因此,对于我们的新部分,计算是:

  • .rsrc部分在0x4200的文件中开始
  • .rsrc文件的段大小是0x19200
  • FileAligment是0x200

计算如下:

 >>> hex(round_up_multiple_of(0x4200 + 0x19200, 0x200)) '0x1d400' 

我们的最后一节从用十六进制编辑器确认的文件中的0x1d400开始:

最后一个位置

最后的步骤

最后一步是必需的,计算可选标题中的SizeOfImage字段。 根据PE规范这个领域是:

图像的大小(以字节为单位)包括所有标题,并将图像加载到内存中。 它必须是SectionAlignment的倍数。

因此,计算是:最后一节的VirtualAddress + VirtualSize ,在SectionAlignment (0x1000)上对齐:

 >>> hex(round_up_multiple_of(0x20000 + 0x1000, 0x1000)) '0x21000' 

图像的新大小

现在,将所有修改保存在CFF资源管理器中并退出。

为新的部分增加空间

最后一步是为最后一部分添加所需的字节。 当我选择Raw size 0x400时,我用十六进制编辑器在Raw Address (0x1d400)处插入0x400字节。

保存你的文件。 如果您按照所有步骤进行操作(在Win 10上进行测试),则可以启动修改后的可执行文件。

如果0x400是不够的尝试体验与新的部分不同的原始大小。

现在你有一个新的空白部分,其余的是由你来修改代码:)