首页 > 解决方案 > 重定位图像时如何前进到下一个内存块

问题描述

基本上我只是想了解这是如何工作的,我看到有几个人使用current_base_relocation = reinterpret_cast<PIMAGE_BASE_RELOCATION>(reinterpret_cast<uint64_t>(current_base_relocation) + current_base_relocation->SizeOfBlock);where current_base_relocation 是指向 PIMAGE_BASE_RELOCATION 基本结构的指针前进到第二个 PIMAGE_BASE_RELOCATION 结构(或第二个重定位块),基本上他添加了结构本身 + 另一个结构和条目的大小并到达第二块内存,但有人可以解释一下吗?例如,为了在映射时修复 pe 文件中的导入,我可以简单地使用 ++struct 前进到内存中的第二个结构,以转到数组中的第二个结构,但我不明白这个是如何工作的。

标签: c++cwindowswinapiportable-executable

解决方案


您问为什么在处理 PE 文件的 IMAGE_DIRECTORY_ENTRY_BASERELOC 目录时,以下代码可以前进到下一个 IMAGE_BASE_RELOCATION 块:

current_base_relocation = reinterpret_cast<PIMAGE_BASE_RELOCATION>(reinterpret_cast<uint64_t>(current_base_relocation) + current_base_relocation->SizeOfBlock);

IMAGE_BASE_RELOCATION 结构是块的标头,并不代表整个块。如果结构确实代表了整个块,您可以使用 current_base_relocation++ 推进它。这就是为您提供 size 成员 (current_base_relocation->SizeOfBlock) 的原因。请注意,此大小包括标头结构 (IMAGE_BASE_RELOCATION) 和后面的数组的大小,以字节为单位。获取 WORD 大小的数据数组的指针计算将是经过 IMAGE_BASE_RELOCATION 结构(标题)的第一个位置,可以这样获得:

word* pCurBlockEntry = (word*)((byte*)current_base_relocation + sizeof(*current_base_relocation))) 

现在回答你的问题。您提供的计算可能是您在循环体中看到的,在它处理了您指出的第一个块之后。它以指向 IMAGE_BASE_RELOCATION 结构的当前指针开始。然后将指针转换为 64 位无符号整数,这样当您向其添加字节大小 (current_base_relocation->SizeOfBlock) 时,您会按字节数而不是 IMAGE_BASE_RELOCATION 结构的数量前进(这将是一个严重的漏洞)。任何无符号整数都可以。使用 64 位无符号整数是因为它与指针的整数大小相同(对于 64 位代码),否则可以使用 32 位无符号整数。

例如,如果没有强制转换并假设 current_base_relocation->SizeOfBlock 恰好是 32,指针算术指示您的指针将前进 32 个 IMAGE_BASE_RELOCATION 结构而不是 32 个字节到下一个块(这将包括当前的 IMAGE_BASE_RELOCATION 结构和尾随数据数组本例中的 12 个 16 位条目)。实际上,我认为这些块都是 4k,至少根据 PE 规范。

就个人而言,当我想将指针推进一个字节大小时,我更喜欢在算术之前将其转换为 byte* 而不是无符号整数。这只是防止在整数和指针之间切换,从而避免编译为 C++ 时的编译器警告。但是,这两种方法都可以工作并达到相同的结果,因此您的代码很好。

将值适当地提前正确的字节数,结果将被转换回 IMAGE_BASE_RELOCATION 指针,因为它现在应该指向下一个块的开头(下一个 IMAGE_BASE_RELOCATION 结构)。

顺便说一句,当您有一个 current_base_relocation->SizeOfBlock 为零的条目时,您就会知道您已经到达了块的末尾。


推荐阅读