重定位图像时如何前进到下一个内存块
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 为零的条目时,你就会知道你已经到达了块的末尾。
【讨论】:
以上是关于重定位图像时如何前进到下一个内存块的主要内容,如果未能解决你的问题,请参考以下文章