/////////////////////////////////////////////////////////////////////////////// // // 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.