2
void
CopySections(const unsigned char *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module)
{
    int i, size;
    unsigned char *codeBase = module->codeBase;
    unsigned char *dest;
    PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers);
    for (i=0; i<module->headers->FileHeader.NumberOfSections; i++, section++) {
        if (section->SizeOfRawData == 0) {
            // section doesn't contain data in the dll itself, but may define
            // uninitialized data
            size = old_headers->OptionalHeader.SectionAlignment;
            if (size > 0) {
                dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
                    size,
                    MEM_COMMIT,
                    PAGE_READWRITE);

                section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest;
                memset(dest, 0, size);
            }

            // section is empty
            continue;
        }

        // commit memory block and copy data from dll
        dest = (unsigned char *)VirtualAlloc(codeBase + section->VirtualAddress,
                            section->SizeOfRawData,
                            MEM_COMMIT,
                            PAGE_READWRITE);
        memcpy(dest, data + section->PointerToRawData, section->SizeOfRawData);
        section->Misc.PhysicalAddress = (DWORD) (POINTER_TYPE) dest;
    }
}

我想从内存中加载一个 dll 文件。上面的代码在http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory中找到。

我还发现作者说:“文件中没有数据的部分(如已使用变量的数据部分)的 SizeOfRawData 为 0,因此您可以使用 OptionalHeader 的 SizeOfInitializedData 或 SizeOfUninitializedData。必须根据位选择哪个标志 IMAGE_SCN_CNT_INITIALIZED_DATA 和 IMAGE_SCN_CNT_UNINITIALIZED_DATA 可以在部分的特征中设置。”

但是我不明白什么时候 SizeOfRawData 为零,为什么提交的内存大小是 SectionAlignment,既不是 SizeOfInitializedData 也不是 SizeOfUninitializedData。

4

1 回答 1

1

根据Microsoft PE 和 COFF 规范, SizeOfRawData 在以下情况下为零:

当一个节只包含未初始化的数据时,该字段 (SizeOfRawData) 应该为零。

(作为旁注,如果该部分仅包含初始化为 0 的初始化数据,这也是正确的。)

SizeOfInitializedData 或 SizeOfUninitializedData 不能在每个部分的基础上使用,因为如果有多个此类部分(引用规范),这些字段是所有已初始化和未初始化部分的总和:

SizeOfInitializedData :初始化数据段的大小,如果有多个数据段,则为所有此类段的总和。

SizeOfUninitializedData :未初始化数据段 (BSS) 的大小,如果有多个 BSS 段,则为所有此类段的总和。

因此,如果您有多个已初始化或未初始化的部分,那么如果您(分别)使用 SizeOfInitializedData 或 SizeOfUninitializedData 字段,您最终会为单个部分分配很多。

它不能是 SectionAlignment (通常设置为系统分配粒度),因为如果 xection 的大小大于分配粒度(通常是 4Kibi 或 4096字节)。

SectionAlignment:当它们被加载到内存中时,节的对齐方式(以字节为单位)。它必须大于或等于 FileAlignment。默认值为体系结构的页面大小。

例如,假设您有 2 个未初始化的数据段(每个段的 SizeOfRawData = 0),每个段 8192 字节。如果您分配:

  • SizeOfUninitializedData :您最终会为每个部分分配 8192 * 2 字节,这太多了。

  • SectionAlignment:你最终会为每个部分分配 4096 (0x1000) 字节,这还不够。

IMO,与您的情况相关的唯一字段是 IMAGE_SECTION_HEADER.VirtualSize:

VirtualSize:加载到内存中的部分的总大小。如果此值大于 SizeOfRawData,则该部分被零填充。该字段仅对可执行图像有效,并且对于目标文件应设置为零。

请注意,VirtualSize 字段未四舍五入(它是内存中所需的确切字节数,不考虑页面粒度)。

因此,如果您有一个 SizeOfRawData = 0 的部分,您应该:

  • 取本节的 VirtualSize 字段
  • 使用 VirtualAlloc() 分配结果大小

您不必四舍五入 VirtualSize,因为 VirtualAlloc() 将负责分配到页面大小粒度的下一个倍数(由GetSystemInfo和 SYSTEM_INFO.dwPageSize 字段给出)。

于 2013-09-15T14:15:39.847 回答