重定位图像时如何前进到下一个内存块

Posted

技术标签:

【中文标题】重定位图像时如何前进到下一个内存块【英文标题】:how to advance to next block of memory when relocating image 【发布时间】:2020-07-08 14:36:26 【问题描述】:

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

【问题讨论】:

你知道它的作用吗? @user253751 是的,我知道,但我唯一不明白的是如何前进到第二块内存,我想了解这个结构在内存中的工作原理 IMAGE_BASE_RELOCATION 是可变大小的结构。在这种情况下,结构的实际大小 - 在 SizeOfBlock 成员内的 bode(header) 中。并移动到数组的下一个元素 - 我们将此值 (SizeOfBlock) 添加到指针。很常见的做法 @RbMm 我没有得到你试图解释的内容 IMAGE_BASE_RELOCATION 是一个结构,我们有一个指向它的指针,为什么我们需要添加它 + sizeOfBlock 我知道 sizeOfBlock 已经有了结构的大小,所以我们就像添加 2 个结构 + 偏移数组来重定位它对我来说没有意义,因为我不明白,你能尽量简单地解释一下吗? 【参考方案1】:

您问为什么在处理 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 为零的条目时,你就会知道你已经到达了块的末尾。

【讨论】:

以上是关于重定位图像时如何前进到下一个内存块的主要内容,如果未能解决你的问题,请参考以下文章

如何在Wps中快速定位到上一次编辑的位置

第16章:基址重定位

重定位与链接脚本

嵌入式Linux裸机开发——重定位relocate

计算机系统篇之链接:静态链接(下)——重定位

计算机系统篇之链接:静态链接(下)——重定位