singrdk/base/boot/SingLdrPc/blpecoff.cpp

495 lines
14 KiB
C++

//++
//
// Copyright (c) Microsoft Corporation
//
// Module Name:
//
// blpecoff.cpp
//
// Abstract:
//
// This module implements PE / COFF support for the boot loader.
//
//--
#include "bl.h"
#define IMAGE_DOS_SIGNATURE 0x05A4D // MZ
#define IMAGE_NT_SIGNATURE 0x000004550 // PE00
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
UINT16 e_magic; // Magic number
UINT16 e_cblp; // Bytes on last page of file
UINT16 e_cp; // Pages in file
UINT16 e_crlc; // Relocations
UINT16 e_cparhdr; // Size of header in paragraphs
UINT16 e_minalloc; // Minimum extra paragraphs needed
UINT16 e_maxalloc; // Maximum extra paragraphs needed
UINT16 e_ss; // Initial (relative) SS value
UINT16 e_sp; // Initial SP value
UINT16 e_csum; // Checksum
UINT16 e_ip; // Initial IP value
UINT16 e_cs; // Initial (relative) CS value
UINT16 e_lfarlc; // File address of relocation table
UINT16 e_ovno; // Overlay number
UINT16 e_res[4]; // Reserved words
UINT16 e_oemid; // OEM identifier (for e_oeminfo)
UINT16 e_oeminfo; // OEM information; e_oemid specific
UINT16 e_res2[10]; // Reserved words
INT32 e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _IMAGE_FILE_HEADER {
UINT16 Machine;
UINT16 NumberOfSections;
UINT32 TimeDateStamp;
UINT32 PointerToSymbolTable;
UINT32 NumberOfSymbols;
UINT16 SizeOfOptionalHeader;
UINT16 Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY {
UINT32 VirtualAddress;
UINT32 Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
#if defined(BOOT_X86)
typedef struct _IMAGE_OPTIONAL_HEADER_32 {
UINT16 Magic;
UINT8 MajorLinkerVersion;
UINT8 MinorLinkerVersion;
UINT32 SizeOfCode;
UINT32 SizeOfInitializedData;
UINT32 SizeOfUninitializedData;
UINT32 AddressOfEntryPoint;
UINT32 BaseOfCode;
UINT32 BaseOfData;
UINT32 ImageBase;
UINT32 SectionAlignment;
UINT32 FileAlignment;
UINT16 MajorOperatingSystemVersion;
UINT16 MinorOperatingSystemVersion;
UINT16 MajorImageVersion;
UINT16 MinorImageVersion;
UINT16 MajorSubsystemVersion;
UINT16 MinorSubsystemVersion;
UINT32 Win32VersionValue;
UINT32 SizeOfImage;
UINT32 SizeOfHeaders;
UINT32 CheckSum;
UINT16 Subsystem;
UINT16 DllCharacteristics;
UINT32 SizeOfStackReserve;
UINT32 SizeOfStackCommit;
UINT32 SizeOfHeapReserve;
UINT32 SizeOfHeapCommit;
UINT32 LoaderFlags;
UINT32 NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_NT_HEADERS32 {
UINT32 Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
#elif defined(BOOT_X64)
typedef struct _IMAGE_OPTIONAL_HEADER64 {
UINT16 Magic;
UINT8 MajorLinkerVersion;
UINT8 MinorLinkerVersion;
UINT32 SizeOfCode;
UINT32 SizeOfInitializedData;
UINT32 SizeOfUninitializedData;
UINT32 AddressOfEntryPoint;
UINT32 BaseOfCode;
UINT64 ImageBase;
UINT32 SectionAlignment;
UINT32 FileAlignment;
UINT16 MajorOperatingSystemVersion;
UINT16 MinorOperatingSystemVersion;
UINT16 MajorImageVersion;
UINT16 MinorImageVersion;
UINT16 MajorSubsystemVersion;
UINT16 MinorSubsystemVersion;
UINT32 Win32VersionValue;
UINT32 SizeOfImage;
UINT32 SizeOfHeaders;
UINT32 CheckSum;
UINT16 Subsystem;
UINT16 DllCharacteristics;
UINT64 SizeOfStackReserve;
UINT64 SizeOfStackCommit;
UINT64 SizeOfHeapReserve;
UINT64 SizeOfHeapCommit;
UINT32 LoaderFlags;
UINT32 NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_NT_HEADERS64 {
UINT32 Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
#endif
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
UINT8 Name[IMAGE_SIZEOF_SHORT_NAME];
union {
UINT32 PhysicalAddress;
UINT32 VirtualSize;
} Misc;
UINT32 VirtualAddress;
UINT32 SizeOfRawData;
UINT32 PointerToRawData;
UINT32 PointerToRelocations;
UINT32 PointerToLinenumbers;
UINT16 NumberOfRelocations;
UINT16 NumberOfLinenumbers;
UINT32 Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct _IMAGE_BASE_RELOCATION {
UINT32 VirtualAddress;
UINT32 SizeOfBlock;
UINT16 TypeOffset[0];
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;
#define IMAGE_REL_BASED_ABSOLUTE 0
#define IMAGE_REL_BASED_HIGHLOW 3
#define IMAGE_REL_BASED_DIR64 10
VOID
BlPeGetVirtualRange(
PVOID Image,
PVOID *VirtualBase,
ULONG_PTR *VirtualSize
)
//++
//
// Routine Description:
//
// This function queries the virtual range for the specified image.
//
// Arguments:
//
// Image - Supplies a pointer to the image.
//
// VirtualBase - Receives the virtual base address of the image.
//
// VirtualSize - Receives the virtual size of the image.
//
//--
{
PIMAGE_DOS_HEADER DosHeader;
UINT32 Index;
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER Section;
UINT32 SectionEnd;
DosHeader = (PIMAGE_DOS_HEADER) Image;
if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
BlRtlPrintf("PECOFF: Invalid image!\n");
BlRtlHalt();
}
NtHeader = (PIMAGE_NT_HEADERS) ((ULONG_PTR) Image + DosHeader->e_lfanew);
if (NtHeader->Signature != IMAGE_NT_SIGNATURE) {
BlRtlPrintf("PECOFF: Invalid image!\n");
BlRtlHalt();
}
if (NtHeader->FileHeader.NumberOfSections == 0) {
BlRtlPrintf("PECOFF: Invalid image!\n");
BlRtlHalt();
}
if ((NtHeader->OptionalHeader.ImageBase % PAGE_SIZE) != 0) {
BlRtlPrintf("PECOFF: Invalid image!\n");
BlRtlHalt();
}
*VirtualBase = (PVOID) NtHeader->OptionalHeader.ImageBase;
*VirtualSize = 0;
Section = (PIMAGE_SECTION_HEADER) (((ULONG_PTR) &NtHeader->OptionalHeader) + NtHeader->FileHeader.SizeOfOptionalHeader);
for (Index = 0; Index < NtHeader->FileHeader.NumberOfSections; Index += 1) {
SectionEnd = Section[Index].VirtualAddress + Section[Index].Misc.VirtualSize;
if (SectionEnd > *VirtualSize) {
*VirtualSize = SectionEnd;
}
}
*VirtualSize = ROUND_UP_TO_PAGES(*VirtualSize);
return;
}
VOID
BlPeApplyFixupBlock(
PIMAGE_BASE_RELOCATION Block,
ULONG_PTR VirtualBase,
ULONG_PTR RelocDiff
)
//++
//
// Routine Description:
//
// This function applies all of the base fixups in the specified block to the image.
//
// Arguments:
//
// Block - Supplies a pointer to the base relocation fixup block.
//
// VirtualBase - Supplies the target address of the image.
//
// RelocDiff - Supplies the offset of the image target address from the base address.
//
//--
{
PUINT16 Reloc;
PUINT16 BlockEnd;
ULONG_PTR BlockBase;
ULONG_PTR Target;
Reloc = Block->TypeOffset;
BlockEnd = (PUINT16) ( ((PUINT8) Block) + Block->SizeOfBlock);
BlockBase = VirtualBase + Block->VirtualAddress;
#if PECOFF_VERBOSE
BlRtlPrintf("PECOFF: Reloc Block %p:\n", Block->VirtualAddress);
#endif
for (; Reloc < BlockEnd; Reloc++) {
Target = BlockBase + (*Reloc & 0xfff);
#if PECOFF_VERBOSE
switch (*Reloc >> 12) {
case IMAGE_REL_BASED_ABSOLUTE: {
BlRtlPrintf("PECOFF: %p: abs:%x \r", (PUINT32) Target, * (PUINT32) Target);
break;
}
case IMAGE_REL_BASED_HIGHLOW: {
BlRtlPrintf("PECOFF: %p: r32:%x->%x \r", (PUINT32) Target, * (PUINT32) Target, * (PUINT32) Target + (UINT32) RelocDiff);
break;
}
case IMAGE_REL_BASED_DIR64: {
BlRtlPrintf("PECOFF: %p: r64:%lx->%lx \r", (PUINT64) Target, * (PUINT64) Target, * (PUINT64) Target + (UINT64) RelocDiff);
break;
}
default: {
BlRtlPrintf("PECOFF: %p: %x ??? \r", (PUINT32) Target, Reloc[0] >> 12);
break;
}
}
#endif
switch (*Reloc >> 12) {
case IMAGE_REL_BASED_ABSOLUTE: {
break;
}
case IMAGE_REL_BASED_HIGHLOW: {
* (PUINT32) Target += (UINT32) RelocDiff;
break;
}
case IMAGE_REL_BASED_DIR64: {
* (PUINT64 *) Target += (UINT64) RelocDiff;
break;
}
default: {
BlRtlPrintf("PECOFF: Illegal relocation.\n");
BlRtlHalt();
}
}
}
}
VOID
BlPeLoadImage(
PVOID LoadBase,
PVOID Image,
PVOID *EntryPoint
)
//++
//
// Routine Description:
//
// This function loads the specified image.
//
// Arguments:
//
// Image - Supplies a pointer to the image to load.
//
// EntryPoint - Receives a pointer to the entry point of the image.
//
//--
{
ULONG_PTR BytesToCopy;
PIMAGE_DOS_HEADER DosHeader;
UINT32 Index;
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER Section;
ULONG_PTR VirtualBase;
ULONG_PTR RelocDiff;
VirtualBase = (ULONG_PTR) LoadBase;
DosHeader = (PIMAGE_DOS_HEADER) Image;
if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
BlRtlPrintf("PECOFF: Missing MZ!\n");
BlRtlHalt();
}
NtHeader = (PIMAGE_NT_HEADERS) ((ULONG_PTR) Image + DosHeader->e_lfanew);
if (NtHeader->Signature != IMAGE_NT_SIGNATURE) {
BlRtlPrintf("PECOFF: Missing PE!\n");
BlRtlHalt();
}
if (NtHeader->FileHeader.NumberOfSections == 0) {
BlRtlPrintf("PECOFF: No sections!\n");
BlRtlHalt();
}
if ((NtHeader->OptionalHeader.ImageBase % PAGE_SIZE) != 0) {
BlRtlPrintf("PECOFF: Not page aligned.\n");
BlRtlHalt();
}
BlRtlCopyMemory((PVOID) VirtualBase,
Image,
NtHeader->OptionalHeader.SizeOfHeaders);
Section = (PIMAGE_SECTION_HEADER) (((ULONG_PTR) &NtHeader->OptionalHeader) + NtHeader->FileHeader.SizeOfOptionalHeader);
for (Index = 0; Index < NtHeader->FileHeader.NumberOfSections; Index += 1) {
BlRtlZeroMemory((PVOID) (VirtualBase + Section[Index].VirtualAddress), Section[Index].Misc.VirtualSize);
if (Section[Index].SizeOfRawData < Section[Index].Misc.VirtualSize) {
BytesToCopy = Section[Index].SizeOfRawData;
} else {
BytesToCopy = Section[Index].Misc.VirtualSize;
}
BlRtlCopyMemory((PVOID) (VirtualBase + Section[Index].VirtualAddress),
(PVOID) (((ULONG_PTR) Image) + Section[Index].PointerToRawData),
BytesToCopy);
#if PECOFF_VERBOSE
{
CHAR Temp[IMAGE_SIZEOF_SHORT_NAME + 1];
BlRtlCopyMemory(Temp,
Section[Index].Name,
IMAGE_SIZEOF_SHORT_NAME);
Temp[IMAGE_SIZEOF_SHORT_NAME] = 0;
BlRtlPrintf("PECOFF: %p ... %p (%p ... %p) %s\n",
VirtualBase + Section[Index].VirtualAddress,
VirtualBase + Section[Index].VirtualAddress + Section[Index].Misc.VirtualSize - 1,
(((ULONG_PTR) Image) + Section[Index].PointerToRawData),
(((ULONG_PTR) Image) + Section[Index].PointerToRawData) + BytesToCopy,
Temp);
}
#endif
}
RelocDiff = VirtualBase - (ULONG_PTR)NtHeader->OptionalHeader.ImageBase;
if (RelocDiff != 0) {
PUINT8 RelocList;
PUINT8 RelocListEnd;
PIMAGE_BASE_RELOCATION Block;
RelocList = (PUINT8) (VirtualBase + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
RelocListEnd = RelocList + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
#if PECOFF_VERBOSE
BlRtlPrintf("PECOFF: Relocs: %p ... %p\n", RelocList, RelocListEnd);
#endif
while (RelocList < RelocListEnd) {
Block = (PIMAGE_BASE_RELOCATION) RelocList;
BlPeApplyFixupBlock(Block, VirtualBase, RelocDiff);
RelocList += Block->SizeOfBlock;
}
}
*EntryPoint = (PVOID) (VirtualBase + NtHeader->OptionalHeader.AddressOfEntryPoint);
return;
}