495 lines
14 KiB
C++
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;
|
|
}
|
|
|