【问题标题】:How is SizeOfImage in the PE optional header computed?PE 可选标头中的 SizeOfImage 是如何计算的?
【发布时间】:2016-12-25 15:49:18
【问题描述】:

PE 可选标头中的 SizeOfImage 是如何计算的?

在尝试学习 PE 格式时,我遇到了可选标头中的 SizeOfImage 字段。

引用文档:

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

但是,我遇到过,如果我错误地设置了这个字段,那么可执行文件将无法运行,并且会显示 error 193(格式错误的可执行文件):

我如何计算 SizeOfImage 字段,如果设置错误,为什么可执行文件不会运行(例如,如果设置为 0x00003000 但不是 0x00004000 或 0x00002000,可执行文件会运行)?

【问题讨论】:

  • 检查checksum 字段(没有双关语)。
  • 您在问两个不同的问题:1 某个标头值是如何计算的? 2 为什么系统会拒绝一个说谎的图像?你真正需要帮助的是哪一个?
  • @IInspectable:问两个问题完全OK。你有什么问题?
  • @elm 在您的个人资料上带有 Peer Pressure 徽章且没有 Informed 徽章我会质疑您是否了解该网站的运作方式。也许采取tour
  • 我什至看到有人在这里问了两个以上的问题。对于那件事我没有任何疑问。如果对您有问题,您无需回答。

标签: windows assembly x86 portable-executable windows-process


【解决方案1】:

我所知道的最安全的方法是遍历每个部分并找到要在内存中最后加载的部分(即最高地址)。您几乎总是可以假设这是最后一部分,如果您信任您的 PE 文件(例如,如果您使用标准链接器等),则直接跳到该部分。您首先计算该部分的数据结束指针,如下所示:

pEndOfLastSection = pLastSection->VirtualAddress + pLastSection->Misc.VirtualSize + pOptionalHeader->ImageBase

pEndOfLastSection 现在代表实际节数据的结尾(因为它存在于文件中,填充到文件对齐,但不填充到内存对齐)并且不包括加载器必须添加的任何填充以确保节完全符合内存部分对齐的粒度。

尽管其他字段似乎存储了向上舍入到下一个最近的“内存”对齐方式的节结尾,但您必须自己对pEndOfLastSection 指针执行此计算。我编写了以下功能,到目前为止它已经为我的目的工作了:

//
// peRoundUpToAlignment() - rounds dwValue up to nearest dwAlign
//
DWORD peRoundUpToAlignment(DWORD dwAlign, DWORD dwVal)
{
    if (dwAlign)
    {
        //do the rounding with bitwise operations...

        //create bit mask of bits to keep
        //  e.g. if section alignment is 0x1000                        1000000000000
        //       we want the following bitmask      11111111111111111111000000000000
        DWORD dwMask = ~(dwAlign-1);

        //round up by adding full alignment (dwAlign-1 since if already aligned we don't want anything to change),
        //  then mask off any lower bits
        dwVal = (dwVal + dwAlign-1) & dwMask;
    }

    return(dwVal);

} //peRoundUpToAlignment()

现在将您的pEndOfLastSecion 传递给舍入函数,如下所示:

//NOTE: we are rounding to memory section alignment, not file
pEndOfLastSectionMem = peRoundUpToAlignment(pOptionalHeader->SectionAlignment,pEndOfLastSection)

现在您有了一个指向 PE 文件末尾的“模拟”指针,因为它将被加载到内存中。注意:上面计算的结束指针实际上指向最后一节的最后一个字节后的 1 个字节;这允许您从它们的基数中减去它们以获得大小。一旦你有最后一节的结束指针,因为它将被加载到内存中,你可以从加载器基数中减去它并获得 PE 文件的大小,因为它应该 被加载到内存中,并且无论加载器可能将 PE 文件重定位到何处,这个大小显然是相同的:

uCalcSizeOfFile = pEndOfLastSectionMem - pOptionalHeader->ImageBase

除非图像被篡改,否则上面uCalcSizeOfFile的计算应该等于pOptionalHeader->SizeOfImage字段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    • 2012-02-05
    • 2021-07-12
    • 2012-04-21
    相关资源
    最近更新 更多