早期版本將記憶體配置寫在函式內部,嚴重降低復用性(如驅動層無法直接呼叫)。改良後將「系統相關的記憶體配置」移至呼叫端,LdrLayoutPe 僅負責依 PE 結構將檔案內容複製到指定基址,職責單一、易於移植。
BOOL LdrLayoutPe(
char *pImage, // 檔案緩衝區
DWORD FileSize, // 檔案大小
char *pRealImageBase, // 目標映射基址(由呼叫端配置)
DWORD SizeOfImage // 映射總大小(來自 OptionalHeader)
) {
PIMAGE_FILE_HEADER pFileHeader;
PIMAGE_SECTION_HEADER pSectionHeader;
char *pSrc, *pDst;
DWORD CopySize, i;
if (!LdrValidateImage(pImage, FileSize)) return FALSE;
pFileHeader = _GetFileHeaderFromPe(pImage);
pSectionHeader = _GetSectionHeaderFromPe(pFileHeader);
// 1. 複製 DOS Header + NT Headers + Section Table
pDst = pRealImageBase;
pSrc = pImage;
CopySize = (char*)pSectionHeader - pImage
+ pFileHeader->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
if (pDst + CopySize >= pRealImageBase + SizeOfImage) return FALSE;
RtlCopyMemory(pDst, pSrc, CopySize);
// 2. 逐區段複製 Raw Data 至 VirtualAddress
for (i = 0; i < pFileHeader->NumberOfSections; ++i) {
if (!pSectionHeader[i].PointerToRawData) continue; // 僅保留虛擬空間的區段(如 .bss)
pDst = pRealImageBase + pSectionHeader[i].VirtualAddress;
pSrc = pImage + pSectionHeader[i].PointerToRawData;
CopySize = pSectionHeader[i].SizeOfRawData;
if (pDst + CopySize >= pRealImageBase + SizeOfImage) return FALSE;
RtlCopyMemory(pDst, pSrc, CopySize);
}
return TRUE;
}
pDst + CopySize 是否超出 SizeOfImage,防止緩衝區溢位。pRealImageBase 符合 SectionAlignment 對齊需求。