378 lines
13 KiB
C++
378 lines
13 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// expandpe.cpp: code to expand PE image into memory.
|
|
//
|
|
|
|
//#define EXPANDPE_VERBOSE 1
|
|
|
|
///////////////////////////////////////////////// Required External Functions.
|
|
//
|
|
void CopyDown(UINT8 *pbDst, UINT8 *pbSrc, UINT32 cbSrc);
|
|
void Zero(uint8 * pbData, uint32 cbData);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
|
|
#define IMAGE_NT_SIGNATURE 0x00004550 // 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
|
|
uint32 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;
|
|
|
|
//
|
|
// Directory format.
|
|
//
|
|
|
|
typedef struct _IMAGE_DATA_DIRECTORY {
|
|
uint32 VirtualAddress;
|
|
uint32 Size;
|
|
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
|
|
|
|
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
|
|
|
|
|
|
//
|
|
// Optional header format.
|
|
//
|
|
|
|
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
|
|
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
|
|
|
|
typedef struct _IMAGE_OPTIONAL_HEADER32 {
|
|
//
|
|
// Standard fields.
|
|
//
|
|
uint16 Magic;
|
|
uint8 MajorLinkerVersion;
|
|
uint8 MinorLinkerVersion;
|
|
uint32 SizeOfCode;
|
|
uint32 SizeOfInitializedData;
|
|
uint32 SizeOfUninitializedData;
|
|
uint32 AddressOfEntryPoint;
|
|
uint32 BaseOfCode;
|
|
uint32 BaseOfData;
|
|
|
|
//
|
|
// NT additional fields.
|
|
//
|
|
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_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 struct _IMAGE_NT_HEADERS32 {
|
|
uint32 Signature;
|
|
IMAGE_FILE_HEADER FileHeader;
|
|
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
|
|
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
|
|
|
|
#define IMAGE_SIZEOF_SHORT_NAME 8
|
|
|
|
typedef struct _IMAGE_SECTION_HEADER {
|
|
uint8 Name[IMAGE_SIZEOF_SHORT_NAME];
|
|
uint32 VirtualSize;
|
|
uint32 VirtualAddress;
|
|
uint32 SizeOfRawData;
|
|
uint32 PointerToRawData;
|
|
uint32 PointerToRelocations;
|
|
uint32 PointerToLinenumbers;
|
|
uint16 NumberOfRelocations;
|
|
uint16 NumberOfLinenumbers;
|
|
uint32 Characteristics;
|
|
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
|
|
|
|
//
|
|
// Directory Entries
|
|
//
|
|
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
|
|
|
|
//
|
|
// Based relocation types.
|
|
//
|
|
#define IMAGE_REL_BASED_ABSOLUTE 0
|
|
#define IMAGE_REL_BASED_HIGH 1
|
|
#define IMAGE_REL_BASED_LOW 2
|
|
#define IMAGE_REL_BASED_HIGHLOW 3
|
|
#define IMAGE_REL_BASED_HIGHADJ 4
|
|
#define IMAGE_REL_BASED_MIPS_JMPADDR 5
|
|
#define IMAGE_REL_BASED_MIPS_JMPADDR16 9
|
|
#define IMAGE_REL_BASED_IA64_IMM64 9
|
|
#define IMAGE_REL_BASED_DIR64 10
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
uintptr SizeOfPeImage(uintptr source, uintptr& base)
|
|
{
|
|
UINT8 * pbImage = (UINT8 *)source;
|
|
uintptr size = 0;
|
|
|
|
IMAGE_DOS_HEADER * pidh = (IMAGE_DOS_HEADER *)pbImage;
|
|
if (pidh->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
return 0;
|
|
}
|
|
|
|
IMAGE_NT_HEADERS32 * pinh = (IMAGE_NT_HEADERS32 *)(pbImage + pidh->e_lfanew);
|
|
IMAGE_NT_HEADERS64 * pinh64 = (IMAGE_NT_HEADERS64 *)(pbImage + pidh->e_lfanew);
|
|
if (pinh->Signature != IMAGE_NT_SIGNATURE) {
|
|
return 0;
|
|
}
|
|
|
|
if ((pinh->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) &&
|
|
(pinh64->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
|
|
return 0;
|
|
}
|
|
|
|
if (pinh->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
base = pinh->OptionalHeader.ImageBase;
|
|
|
|
if (size < pinh->OptionalHeader.SizeOfHeaders) {
|
|
size = pinh->OptionalHeader.SizeOfHeaders;
|
|
}
|
|
}
|
|
else if (pinh64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
|
base = (uintptr)pinh64->OptionalHeader.ImageBase;
|
|
|
|
if (size < pinh->OptionalHeader.SizeOfHeaders) {
|
|
size = pinh->OptionalHeader.SizeOfHeaders;
|
|
}
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
|
|
IMAGE_SECTION_HEADER * pish = (IMAGE_SECTION_HEADER *)
|
|
(((uintptr)&pinh->OptionalHeader) + pinh->FileHeader.SizeOfOptionalHeader);
|
|
for (int i = 0; i < pinh->FileHeader.NumberOfSections; i++) {
|
|
uint8* pbDst = (uint8 *)base + pish[i].VirtualAddress;
|
|
uint8* pbSrc = pbImage + pish[i].PointerToRawData;
|
|
uint32 cbSrc = (pish[i].VirtualSize < pish[i].SizeOfRawData)
|
|
? pish[i].VirtualSize : pish[i].SizeOfRawData;
|
|
|
|
if (size < pish[i].VirtualAddress + pish[i].VirtualSize) {
|
|
size = pish[i].VirtualAddress + pish[i].VirtualSize;
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
uintptr ExpandPeImage(uintptr dst, uintptr src)
|
|
{
|
|
UINT8 * pbImage = (UINT8 *)src;
|
|
|
|
IMAGE_DOS_HEADER * pidh = (IMAGE_DOS_HEADER *)pbImage;
|
|
if (pidh->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
printf("Mismatch MZ Signature: %04x != %04x\n",
|
|
pidh->e_magic, IMAGE_DOS_SIGNATURE);
|
|
return 0;
|
|
}
|
|
|
|
IMAGE_NT_HEADERS32 * pinh = (IMAGE_NT_HEADERS32 *)(pbImage + pidh->e_lfanew);
|
|
IMAGE_NT_HEADERS64 * pinh64 = (IMAGE_NT_HEADERS64 *)(pbImage + pidh->e_lfanew);
|
|
if (pinh->Signature != IMAGE_NT_SIGNATURE) {
|
|
printf("Mismatched NT Signature: %08x != %08x\n",
|
|
pinh->Signature, IMAGE_NT_SIGNATURE);
|
|
return 0;
|
|
}
|
|
|
|
if ((pinh->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) &&
|
|
(pinh64->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)) {
|
|
printf("Mismatched PE Signature: %08x != %08x or %08x != %08x\n",
|
|
pinh->OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR32_MAGIC,
|
|
pinh64->OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR64_MAGIC);
|
|
return 0;
|
|
}
|
|
|
|
uintptr entry = 0;
|
|
uintptr diff = 0;
|
|
|
|
if (pinh->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
diff = dst - pinh->OptionalHeader.ImageBase;
|
|
entry = dst + pinh->OptionalHeader.AddressOfEntryPoint;
|
|
|
|
CopyDown((uint8*)dst, pbImage, pinh->OptionalHeader.SizeOfHeaders);
|
|
}
|
|
else if (pinh64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
|
diff = dst - (uintptr)pinh64->OptionalHeader.ImageBase;
|
|
entry = dst + pinh64->OptionalHeader.AddressOfEntryPoint;
|
|
|
|
CopyDown((uint8*)dst, pbImage, pinh64->OptionalHeader.SizeOfHeaders);
|
|
}
|
|
else {
|
|
printf("Forgot to update IMAGE_NT_OPTIONAL test!\n");
|
|
return 0;
|
|
}
|
|
|
|
IMAGE_SECTION_HEADER * pish = (IMAGE_SECTION_HEADER *)
|
|
(((uintptr)&pinh->OptionalHeader) + pinh->FileHeader.SizeOfOptionalHeader);
|
|
#if EXPANDPE_VERBOSE
|
|
printf(" Section_ VirtAddr VirtSize _RawAddr _RawSize DestAddr CopySize SorcAddr\n");
|
|
#endif
|
|
for (int i = 0; i < pinh->FileHeader.NumberOfSections; i++) {
|
|
uint8* pbDst = (uint8 *)dst + pish[i].VirtualAddress;
|
|
uint8* pbSrc = pbImage + pish[i].PointerToRawData;
|
|
uint32 cbSrc = (pish[i].VirtualSize < pish[i].SizeOfRawData)
|
|
? pish[i].VirtualSize : pish[i].SizeOfRawData;
|
|
|
|
#if EXPANDPE_VERBOSE
|
|
printf(" %-8.8s %08x %8x %08x %8x %8x %8x %8x\n",
|
|
pish[i].Name,
|
|
pish[i].VirtualAddress,
|
|
pish[i].VirtualSize,
|
|
pish[i].PointerToRawData,
|
|
pish[i].SizeOfRawData,
|
|
pbDst,
|
|
cbSrc,
|
|
pbSrc);
|
|
#endif
|
|
|
|
Zero(pbDst, pish[i].VirtualSize);
|
|
CopyDown(pbDst, pbSrc, cbSrc);
|
|
}
|
|
|
|
// Process the relocations.
|
|
if (diff != 0) {
|
|
IMAGE_DATA_DIRECTORY * pidd
|
|
= &pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
|
|
uint8* pbReloc = (uint8*)dst + pidd->VirtualAddress;
|
|
uint8* pbRelocEnd = pbReloc + pidd->Size;
|
|
|
|
#if EXPANDPE_VERBOSE
|
|
printf("Relocs: %08x..%08x\n", pbReloc, pbRelocEnd);
|
|
#endif
|
|
while (pbReloc < pbRelocEnd) {
|
|
uint32 * ph = (uint32 *)pbReloc;
|
|
|
|
#if EXPANDPE_VERBOSE
|
|
printf(" %08x..%08x\n", ph[0], ph[1]);
|
|
#endif
|
|
uint16 * pr = (uint16 *)(pbReloc + 8);
|
|
uint16 * prEnd = (uint16 *)(pbReloc + ph[1]);
|
|
uintptr va = dst + ph[0];
|
|
|
|
for (; pr < prEnd; pr++) {
|
|
uintptr rva = va + (pr[0] & 0xfff);
|
|
|
|
switch (pr[0] >> 12) {
|
|
case IMAGE_REL_BASED_ABSOLUTE:
|
|
#if EXPANDPE_VERBOSE
|
|
printf(" %p: abs:%x\n", (uint32*)rva, *(uint32*)rva);
|
|
#endif
|
|
break;
|
|
case IMAGE_REL_BASED_HIGHLOW: // 32-bit reloc
|
|
#if EXPANDPE_VERBOSE
|
|
printf(" %p: r32:%x->%x\n",
|
|
(uint32*)rva, *(uint32*)rva, *(uint32*)rva + (uint32)diff);
|
|
#endif
|
|
*(uint32*)rva += (uint32)diff;
|
|
break;
|
|
case IMAGE_REL_BASED_DIR64: // 64-bit reloc
|
|
#if EXPANDPE_VERBOSE
|
|
printf(" %p: r64:%lx->%lx\n",
|
|
(uint64*)rva, *(uint64*)rva, *(uint64*)rva + (uint64)diff);
|
|
#endif
|
|
*(uint64*)rva += (uint64)diff;
|
|
break;
|
|
default:
|
|
printf("%p: %x --- Unknown relocation type!\n", (uint32*)rva, pr[0] >> 12);
|
|
return 0;
|
|
}
|
|
}
|
|
pbReloc = (uint8 *)prEnd;
|
|
}
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
// End of File.
|