【问题标题】:How do I make space for my code cave in a Windows PE 32bit executable如何在 Windows PE 32 位可执行文件中为我的代码洞穴腾出空间
【发布时间】:2016-02-28 17:10:13
【问题描述】:

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

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

所以问题来了:我如何为我的代码洞穴腾出空间?我不想搜索编译器留下的空白空间,我想为我的代码提供干净整洁的 1000h 字节。一个教程和一个关于如何在不破坏游戏的情况下做到这一点的详细解释会很棒! (是的,我实际上是在破解扫雷)

【问题讨论】:

    标签: windows assembly x86 portable-executable


    【解决方案1】:

    如果不使以下部分无效(通常是因为它使这些部分中的偏移量和地址无效),则无法增加部分的大小。这仍然是可能的,但它极易出错,并且当您有更简单的解决方案时不值得麻烦。

    通常,您只需在PE 的末尾添加一个部分,然后从代码部分跳转到那里。代码部分(代码洞穴)的末尾通常有一点空间,因此您可以将 JMP(或一些代码存根)放在那里以重定向到新部分。您还可以为数据或新资源或您想要的任何内容添加其他新部分。


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

    这个文件非常特殊,因此添加新部分比平时要困难一些。

    开始吧!

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

    通常有一些空间可以添加一个新的部分,但在这种特殊情况下,没有空间......最后一个部分的标题紧跟在后面。

    从内容来看,这可能是绑定的导入目录,在CFF explorer中确认(绑定目录的偏移量为0x248):

    绑定的导入目录在今天已经没有用了,尤其是使用 ASLR,所以我们可以将整个目录清零(它的大小为 0xA8 字节,如上一个屏幕截图所示):

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

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

    添加新部分

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

    转到部分标题并添加一个新部分(您可以直接在 CFF 资源管理器中进行操作;我命名为 .foobar,请注意部分名称最多 8 个字符,不要'不需要以 NULL 字节结尾):

    你需要选择两个数字:

    • 新部分的原始大小(我选择了 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'
    

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

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

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

    计算如下:

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

    我们的最后一部分从文件中的原始地址 0x1d400 开始,使用十六进制编辑器确认:

    最后的步骤

    需要最后一步,计算 Optional 标头中的 SizeOfImage 字段。根据 PE 规范,该字段为:

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

    因此计算可以简化为:最后一节的VirtualAddress + VirtualSize,对齐SectionAlignment (0x1000):

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

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

    为新部分添加空间

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

    保存文件。如果您按照所有步骤操作,它必须按原样工作(在 Win 10 上测试),并且您可以启动修改后的可执行文件而不会出现任何错误。

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

    现在你有了一个新的空白部分,剩下的就是你修改代码了:)

    【讨论】:

    • 是的,但正如我之前提到的,我尝试添加新部分,但它损坏了文件,Windows 一直说“这不是 Windows 32 可执行文件”。你能给我更详细的解释吗?你甚至可以从我的链接下载扫雷器并尝试向其中添加新部分
    • 谢谢,你无法相信我有多爱你!
    猜你喜欢
    • 2011-03-01
    • 2011-08-02
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 2012-07-27
    • 2022-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多