-/* $Id$
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/pe.c
#include <ntoskrnl.h>
//#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
#include <reactos/exeformat.h>
static ULONG SectionCharacteristicsToProtect[16] =
{
- PAGE_NOACCESS, /* 0 = NONE */
- PAGE_NOACCESS, /* 1 = SHARED */
- PAGE_EXECUTE, /* 2 = EXECUTABLE */
- PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
- PAGE_READONLY, /* 4 = READABLE */
- PAGE_READONLY, /* 5 = READABLE, SHARED */
- PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
- PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
- /*
- * FIXME? do we really need the WriteCopy field in segments? can't we use
- * PAGE_WRITECOPY here?
- */
- PAGE_READWRITE, /* 8 = WRITABLE */
- PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
- PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
- PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
- PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
- PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
- PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
- PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
+ PAGE_NOACCESS, /* 0 = NONE */
+ PAGE_NOACCESS, /* 1 = SHARED */
+ PAGE_EXECUTE, /* 2 = EXECUTABLE */
+ PAGE_EXECUTE, /* 3 = EXECUTABLE, SHARED */
+ PAGE_READONLY, /* 4 = READABLE */
+ PAGE_READONLY, /* 5 = READABLE, SHARED */
+ PAGE_EXECUTE_READ, /* 6 = READABLE, EXECUTABLE */
+ PAGE_EXECUTE_READ, /* 7 = READABLE, EXECUTABLE, SHARED */
+ /*
+ * FIXME? do we really need the WriteCopy field in segments? can't we use
+ * PAGE_WRITECOPY here?
+ */
+ PAGE_READWRITE, /* 8 = WRITABLE */
+ PAGE_READWRITE, /* 9 = WRITABLE, SHARED */
+ PAGE_EXECUTE_READWRITE, /* 10 = WRITABLE, EXECUTABLE */
+ PAGE_EXECUTE_READWRITE, /* 11 = WRITABLE, EXECUTABLE, SHARED */
+ PAGE_READWRITE, /* 12 = WRITABLE, READABLE */
+ PAGE_READWRITE, /* 13 = WRITABLE, READABLE, SHARED */
+ PAGE_EXECUTE_READWRITE, /* 14 = WRITABLE, READABLE, EXECUTABLE */
+ PAGE_EXECUTE_READWRITE, /* 15 = WRITABLE, READABLE, EXECUTABLE, SHARED */
};
/* TODO: Intsafe should be made into a library, as it's generally useful */
-static __inline BOOLEAN Intsafe_CanAddULongPtr
-(
- IN ULONG_PTR Addend1,
- IN ULONG_PTR Addend2
-)
+static __inline BOOLEAN Intsafe_CanAddULongPtr(IN ULONG_PTR Addend1, IN ULONG_PTR Addend2)
{
- return Addend1 <= (MAXULONG_PTR - Addend2);
+ return Addend1 <= (MAXULONG_PTR - Addend2);
}
-#ifndef MAXLONGLONG
-#define MAXLONGLONG ((LONGLONG)((~((ULONGLONG)0)) >> 1))
-#endif
-
-static __inline BOOLEAN Intsafe_CanAddLong64
-(
- IN LONG64 Addend1,
- IN LONG64 Addend2
-)
+static __inline BOOLEAN Intsafe_CanAddLong64(IN LONG64 Addend1, IN LONG64 Addend2)
{
- return Addend1 <= (MAXLONGLONG - Addend2);
+ return Addend1 <= (MAXLONGLONG - Addend2);
}
-static __inline BOOLEAN Intsafe_CanAddULong32
-(
- IN ULONG Addend1,
- IN ULONG Addend2
-)
+static __inline BOOLEAN Intsafe_CanAddULong32(IN ULONG Addend1, IN ULONG Addend2)
{
- return Addend1 <= (MAXULONG - Addend2);
+ return Addend1 <= (MAXULONG - Addend2);
}
-static __inline BOOLEAN Intsafe_AddULong32
-(
- OUT PULONG Result,
- IN ULONG Addend1,
- IN ULONG Addend2
-)
+static __inline BOOLEAN Intsafe_AddULong32(OUT PULONG Result, IN ULONG Addend1, IN ULONG Addend2)
{
- if(!Intsafe_CanAddULong32(Addend1, Addend2))
- return FALSE;
+ if(!Intsafe_CanAddULong32(Addend1, Addend2))
+ return FALSE;
- *Result = Addend1 + Addend2;
- return TRUE;
+ *Result = Addend1 + Addend2;
+ return TRUE;
}
-static __inline BOOLEAN Intsafe_CanMulULong32
-(
- IN ULONG Factor1,
- IN ULONG Factor2
-)
+static __inline BOOLEAN Intsafe_CanMulULong32(IN ULONG Factor1, IN ULONG Factor2)
{
- return Factor1 <= (MAXULONG / Factor2);
+ return Factor1 <= (MAXULONG / Factor2);
}
-static __inline BOOLEAN Intsafe_CanOffsetPointer
-(
- IN CONST VOID * Pointer,
- IN SIZE_T Offset
-)
+static __inline BOOLEAN Intsafe_CanOffsetPointer(IN CONST VOID * Pointer, IN SIZE_T Offset)
{
- /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
- return Intsafe_CanAddULongPtr((ULONG_PTR)Pointer, Offset);
+ /* FIXME: (PVOID)MAXULONG_PTR isn't necessarily a valid address */
+ return Intsafe_CanAddULongPtr((ULONG_PTR)Pointer, Offset);
}
/* TODO: these are standard DDK/PSDK macros */
#ifndef RTL_CONTAINS_FIELD
#define RTL_CONTAINS_FIELD(P_, SIZE_, FIELD_) \
- ((((char *)(P_)) + (SIZE_)) > (((char *)(&((P_)->FIELD_))) + sizeof((P_)->FIELD_)))
+ ((ULONG_PTR)(P_) + (ULONG_PTR)(SIZE_) > (ULONG_PTR)&((P_)->FIELD_) + sizeof((P_)->FIELD_))
#endif
static __inline BOOLEAN IsPowerOf2(IN ULONG Number)
{
- if(Number == 0)
- return FALSE;
-
- while((Number % 2) == 0)
- Number /= 2;
-
- return Number == 1;
+ if(Number == 0)
+ return FALSE;
+ return (Number & (Number - 1)) == 0;
}
static __inline ULONG ModPow2(IN ULONG Address, IN ULONG Alignment)
{
- ASSERT(IsPowerOf2(Alignment));
- return Address & (Alignment - 1);
+ ASSERT(IsPowerOf2(Alignment));
+ return Address & (Alignment - 1);
}
static __inline BOOLEAN IsAligned(IN ULONG Address, IN ULONG Alignment)
{
- return ModPow2(Address, Alignment) == 0;
+ return ModPow2(Address, Alignment) == 0;
}
-static __inline BOOLEAN AlignUp
-(
- OUT PULONG AlignedAddress,
- IN ULONG Address,
- IN ULONG Alignment
-)
+static __inline BOOLEAN AlignUp(OUT PULONG AlignedAddress, IN ULONG Address, IN ULONG Alignment)
{
- ULONG nExcess = ModPow2(Address, Alignment);
-
- if(nExcess == 0)
- {
- *AlignedAddress = Address;
- return nExcess == 0;
- }
- else
- return Intsafe_AddULong32(AlignedAddress, Address, Alignment - nExcess);
+ ULONG nExcess = ModPow2(Address, Alignment);
+
+ if(nExcess == 0)
+ {
+ *AlignedAddress = Address;
+ return nExcess == 0;
+ }
+ else
+ return Intsafe_AddULong32(AlignedAddress, Address, Alignment - nExcess);
}
#define PEFMT_FIELDS_EQUAL(TYPE1_, TYPE2_, FIELD_) \
(RTL_FIELD_SIZE(TYPE1_, FIELD_) == RTL_FIELD_SIZE(TYPE2_, FIELD_)) \
)
-/*
- References:
- [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
- File Format Specification", revision 6.0 (February 1999)
-*/
-NTSTATUS NTAPI PeFmtCreateSection
-(
- IN CONST VOID * FileHeader,
- IN SIZE_T FileHeaderSize,
- IN PVOID File,
- OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
- OUT PULONG Flags,
- IN PEXEFMT_CB_READ_FILE ReadFileCb,
- IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
-)
-{
- NTSTATUS nStatus;
- ULONG cbFileHeaderOffsetSize;
- ULONG cbSectionHeadersOffset;
- ULONG cbSectionHeadersSize;
- ULONG cbSectionHeadersOffsetSize;
- ULONG cbOptHeaderSize;
- ULONG cbHeadersSize;
- ULONG nSectionAlignment;
- ULONG nFileAlignment;
- const IMAGE_DOS_HEADER * pidhDosHeader;
- const IMAGE_NT_HEADERS32 * pinhNtHeader;
- const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
- const IMAGE_SECTION_HEADER * pishSectionHeaders;
- PMM_SECTION_SEGMENT pssSegments;
- LARGE_INTEGER lnOffset;
- PVOID pBuffer;
- ULONG nPrevVirtualEndOfSegment;
- ULONG nFileSizeOfHeaders;
- ULONG i;
-
- ASSERT(FileHeader);
- ASSERT(FileHeaderSize > 0);
- ASSERT(File);
- ASSERT(ImageSectionObject);
- ASSERT(ReadFileCb);
- ASSERT(AllocateSegmentsCb);
-
- ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
-
- ASSERT(FileHeaderSize >= sizeof(IMAGE_DOS_HEADER));
- ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
-#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
- pBuffer = NULL;
- pidhDosHeader = FileHeader;
-
- /* DOS HEADER */
- nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
-
- /* no MZ signature */
- if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
- DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
-
- /* not a Windows executable */
- if(pidhDosHeader->e_lfanew <= 0)
- DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
-
- /* NT HEADER */
- nStatus = STATUS_INVALID_IMAGE_FORMAT;
-
- if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
- DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
-
- if(FileHeaderSize < cbFileHeaderOffsetSize)
- pinhNtHeader = NULL;
- else
- {
- /*
- we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
- and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
- */
- ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
- pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
- }
-
- ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
- ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
- ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
- ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
-
- /*
- the buffer doesn't contain the NT file header, or the alignment is wrong: we
- need to read the header from the file
- */
- if
- (
- FileHeaderSize < cbFileHeaderOffsetSize ||
- (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0
- )
- {
- ULONG cbNtHeaderSize;
- ULONG cbReadSize;
- PVOID pData;
-l_ReadHeaderFromFile:
- lnOffset.QuadPart = pidhDosHeader->e_lfanew;
- /* read the header from the file */
- nStatus = ReadFileCb
- (
- File,
- &lnOffset,
- sizeof(IMAGE_NT_HEADERS64),
- &pData,
- &pBuffer,
- &cbReadSize
- );
- if(!NT_SUCCESS(nStatus))
- DIE(("ReadFile failed, status %08X\n", nStatus));
- ASSERT(pData);
- ASSERT(pBuffer);
- ASSERT(cbReadSize > 0);
- nStatus = STATUS_INVALID_IMAGE_FORMAT;
- /* the buffer doesn't contain the file header */
- if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
- DIE(("The file doesn't contain the PE file header\n"));
- pinhNtHeader = pData;
- /* object still not aligned: copy it to the beginning of the buffer */
- if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
- {
- ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
- RtlMoveMemory(pBuffer, pData, cbReadSize);
- pinhNtHeader = pBuffer;
- }
- /* invalid NT header */
- if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
- DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
- if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
- DIE(("The full NT header is too large\n"));
- nStatus = STATUS_UNSUCCESSFUL;
- /* the buffer doesn't contain the whole NT header */
- if(cbReadSize < cbNtHeaderSize)
- DIE(("The file doesn't contain the full NT header\n"));
- }
- else
- {
- ULONG cbOptHeaderOffsetSize;
- nStatus = STATUS_INVALID_IMAGE_FORMAT;
- /* don't trust an invalid NT header */
- if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
- DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
- if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
- DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
- if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
- DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
- /* the buffer doesn't contain the whole NT header: read it from the file */
- if(cbOptHeaderOffsetSize > FileHeaderSize)
- goto l_ReadHeaderFromFile;
- }
- /* read information from the NT header */
- piohOptHeader = &pinhNtHeader->OptionalHeader;
- cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
- nStatus = STATUS_INVALID_IMAGE_FORMAT;
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
- if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
- DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
- /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
- switch(piohOptHeader->Magic)
- {
- case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
- case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
- break;
- default:
- DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
- }
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
- if
- (
- RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
- RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment)
- )
- {
- /* See [1], section 3.4.2 */
- if(piohOptHeader->SectionAlignment < PAGE_SIZE)
- {
- if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
- DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
- }
- else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
- DIE(("The section alignment is smaller than the file alignment\n"));
-
- nSectionAlignment = piohOptHeader->SectionAlignment;
- nFileAlignment = piohOptHeader->FileAlignment;
-
- if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
- DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
- }
- else
- {
- nSectionAlignment = PAGE_SIZE;
- nFileAlignment = PAGE_SIZE;
- }
-
- ASSERT(IsPowerOf2(nSectionAlignment));
- ASSERT(IsPowerOf2(nFileAlignment));
-
- switch(piohOptHeader->Magic)
- {
- /* PE32 */
- case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
- {
- if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
- ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
-
- if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
- ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve;
-
- if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
- ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit;
-
- break;
- }
-
- /* PE32+ */
- case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
- {
- const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
-
- pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
-
- if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
- {
- if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
- DIE(("ImageBase exceeds the address space\n"));
-
- ImageSectionObject->ImageBase = pioh64OptHeader->ImageBase;
- }
-
- if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
- {
- if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
- DIE(("SizeOfStackReserve exceeds the address space\n"));
-
- ImageSectionObject->StackReserve = pioh64OptHeader->SizeOfStackReserve;
- }
-
- if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
- {
- if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
- DIE(("SizeOfStackCommit exceeds the address space\n"));
-
- ImageSectionObject->StackCommit = pioh64OptHeader->SizeOfStackCommit;
- }
-
- break;
- }
- }
-
- /* [1], section 3.4.2 */
- if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
- DIE(("ImageBase is not aligned on a 64KB boundary"));
-
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
-
- if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
- {
- ImageSectionObject->Subsystem = piohOptHeader->Subsystem;
-
- if
- (
- RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
- RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion)
- )
- {
- ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion;
- ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion;
- }
- }
-
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
-
- if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
- ImageSectionObject->EntryPoint = piohOptHeader->AddressOfEntryPoint;
-
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
-
- if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
- ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0;
- else
- ImageSectionObject->Executable = TRUE;
-
- ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
- ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine;
-
- /* SECTION HEADERS */
- nStatus = STATUS_INVALID_IMAGE_FORMAT;
-
- /* see [1], section 3.3 */
- if(pinhNtHeader->FileHeader.NumberOfSections > 96)
- DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
- /*
- the additional segment is for the file's headers. They need to be present for
- the benefit of the dynamic loader (to locate exports, defaults for thread
- parameters, resources, etc.)
- */
- ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
-
- /* file offset for the section headers */
- if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
- DIE(("Offset overflow\n"));
-
- if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
- DIE(("Offset overflow\n"));
-
- /* size of the section headers */
- ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
- cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
-
- if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
- DIE(("Section headers too large\n"));
-
- ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
-
- /* size of the executable's headers */
- if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
- {
- if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
- DIE(("SizeOfHeaders is not aligned\n"));
-
- if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
- DIE(("The section headers overflow SizeOfHeaders\n"));
-
- cbHeadersSize = piohOptHeader->SizeOfHeaders;
- }
- else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
- DIE(("Overflow aligning the size of headers\n"));
-
- if(pBuffer)
- {
- ExFreePool(pBuffer);
- pBuffer = NULL;
- }
- /* WARNING: pinhNtHeader IS NO LONGER USABLE */
- /* WARNING: piohOptHeader IS NO LONGER USABLE */
- /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
-
- if(FileHeaderSize < cbSectionHeadersOffsetSize)
- pishSectionHeaders = NULL;
- else
- {
- /*
- we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
- and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
- */
- ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
- pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
- }
-
- /*
- the buffer doesn't contain the section headers, or the alignment is wrong:
- read the headers from the file
- */
- if
- (
- FileHeaderSize < cbSectionHeadersOffsetSize ||
- (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0
- )
- {
- PVOID pData;
- ULONG cbReadSize;
-
- lnOffset.QuadPart = cbSectionHeadersOffset;
-
- /* read the header from the file */
- nStatus = ReadFileCb
- (
- File,
- &lnOffset,
- cbSectionHeadersSize,
- &pData,
- &pBuffer,
- &cbReadSize
- );
-
- if(!NT_SUCCESS(nStatus))
- DIE(("ReadFile failed with status %08X\n", nStatus));
-
- ASSERT(pData);
- ASSERT(pBuffer);
- ASSERT(cbReadSize > 0);
-
- nStatus = STATUS_INVALID_IMAGE_FORMAT;
-
- /* the buffer doesn't contain all the section headers */
- if(cbReadSize < cbSectionHeadersSize)
- DIE(("The file doesn't contain all of the section headers\n"));
-
- pishSectionHeaders = pData;
-
- /* object still not aligned: copy it to the beginning of the buffer */
- if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
- {
- ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
- RtlMoveMemory(pBuffer, pData, cbReadSize);
- pishSectionHeaders = pBuffer;
- }
- }
-
- /* SEGMENTS */
- /* allocate the segments */
- nStatus = STATUS_INSUFFICIENT_RESOURCES;
- ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
-
- if(ImageSectionObject->Segments == NULL)
- DIE(("AllocateSegments failed\n"));
-
- /* initialize the headers segment */
- pssSegments = ImageSectionObject->Segments;
-
- ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
-
- if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
- DIE(("Cannot align the size of the section headers\n"));
-
- if(!AlignUp(&nPrevVirtualEndOfSegment, cbHeadersSize, nSectionAlignment))
- DIE(("Cannot align the size of the section headers\n"));
-
- pssSegments[0].FileOffset = 0;
- pssSegments[0].Protection = PAGE_READONLY;
- pssSegments[0].Length = nPrevVirtualEndOfSegment;
- pssSegments[0].RawLength = nFileSizeOfHeaders;
- pssSegments[0].VirtualAddress = 0;
- pssSegments[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
- pssSegments[0].WriteCopy = TRUE;
-
- /* skip the headers segment */
- ++ pssSegments;
-
- nStatus = STATUS_INVALID_IMAGE_FORMAT;
-
- /* convert the executable sections into segments. See also [1], section 4 */
- for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
- {
- ULONG nCharacteristics;
-
- /* validate the alignment */
- if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
- DIE(("VirtualAddress[%u] is not aligned\n", i));
-
- /* sections must be contiguous, ordered by base address and non-overlapping */
- if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
- DIE(("Memory gap between section %u and the previous\n", i));
-
- /* ignore explicit BSS sections */
- if(pishSectionHeaders[i].SizeOfRawData != 0)
- {
- /* validate the alignment */
-#if 0 /* Yes, this should be a multiple of FileAlignment, but there's
- stuff out there that isn't. We can cope with that */
- if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
- DIE(("SizeOfRawData[%u] is not aligned\n", i));
+
+
+
+//
+// FIXME: All this whitespace is "padding" so the C_ASSERTs aren't on the same lines as asserts in other headers.
+// This is necessary because of the way we define C_ASSERT in a gcc compatible way.
+// This can be removed once we upgrade to gcc 4.3.x or later (which implements __COUNTER__).
+//
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//
+// PeFmtCreateSection depends on the following:
+//
+C_ASSERT(EXEFMT_LOAD_HEADER_SIZE >= sizeof(IMAGE_DOS_HEADER));
+C_ASSERT(sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64));
+
+C_ASSERT(TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == TYPE_ALIGNMENT(IMAGE_NT_HEADERS64));
+C_ASSERT(RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader) == RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS64, FileHeader));
+C_ASSERT(FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader) == FIELD_OFFSET(IMAGE_NT_HEADERS64, OptionalHeader));
+
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Magic));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SectionAlignment));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, FileAlignment));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, Subsystem));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MinorSubsystemVersion));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, MajorSubsystemVersion));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));
+C_ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfHeaders));
+
+/*
+ References:
+ [1] Microsoft Corporation, "Microsoft Portable Executable and Common Object
+ File Format Specification", revision 6.0 (February 1999)
+*/
+NTSTATUS NTAPI PeFmtCreateSection(IN CONST VOID * FileHeader,
+ IN SIZE_T FileHeaderSize,
+ IN PVOID File,
+ OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject,
+ OUT PULONG Flags,
+ IN PEXEFMT_CB_READ_FILE ReadFileCb,
+ IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb)
+{
+ NTSTATUS nStatus;
+ ULONG cbFileHeaderOffsetSize = 0;
+ ULONG cbSectionHeadersOffset = 0;
+ ULONG cbSectionHeadersSize;
+ ULONG cbSectionHeadersOffsetSize = 0;
+ ULONG cbOptHeaderSize;
+ ULONG cbHeadersSize = 0;
+ ULONG nSectionAlignment;
+ ULONG nFileAlignment;
+ const IMAGE_DOS_HEADER * pidhDosHeader;
+ const IMAGE_NT_HEADERS32 * pinhNtHeader;
+ const IMAGE_OPTIONAL_HEADER32 * piohOptHeader;
+ const IMAGE_SECTION_HEADER * pishSectionHeaders;
+ PMM_SECTION_SEGMENT pssSegments;
+ LARGE_INTEGER lnOffset;
+ PVOID pBuffer;
+ ULONG nPrevVirtualEndOfSegment = 0;
+ ULONG nFileSizeOfHeaders = 0;
+ ULONG i;
+
+ ASSERT(FileHeader);
+ ASSERT(FileHeaderSize > 0);
+ ASSERT(File);
+ ASSERT(ImageSectionObject);
+ ASSERT(ReadFileCb);
+ ASSERT(AllocateSegmentsCb);
+
+ ASSERT(Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize));
+
+ ASSERT(((UINT_PTR)FileHeader % TYPE_ALIGNMENT(IMAGE_DOS_HEADER)) == 0);
+
+#define DIE(ARGS_) { DPRINT ARGS_; goto l_Return; }
+
+ pBuffer = NULL;
+ pidhDosHeader = FileHeader;
+
+ /* DOS HEADER */
+ nStatus = STATUS_ROS_EXEFMT_UNKNOWN_FORMAT;
+
+ /* image too small to be an MZ executable */
+ if(FileHeaderSize < sizeof(IMAGE_DOS_HEADER))
+ DIE(("Too small to be an MZ executable, size is %lu\n", FileHeaderSize));
+
+ /* no MZ signature */
+ if(pidhDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+ DIE(("No MZ signature found, e_magic is %hX\n", pidhDosHeader->e_magic));
+
+ /* not a Windows executable */
+ if(pidhDosHeader->e_lfanew <= 0)
+ DIE(("Not a Windows executable, e_lfanew is %d\n", pidhDosHeader->e_lfanew));
+
+ /* NT HEADER */
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ if(!Intsafe_AddULong32(&cbFileHeaderOffsetSize, pidhDosHeader->e_lfanew, RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader)))
+ DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
+
+ if(FileHeaderSize < cbFileHeaderOffsetSize)
+ pinhNtHeader = NULL;
+ else
+ {
+ /*
+ * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
+ * and FileHeaderSize >= cbFileHeaderOffsetSize, so this holds true too
+ */
+ ASSERT(Intsafe_CanOffsetPointer(FileHeader, pidhDosHeader->e_lfanew));
+ pinhNtHeader = (PVOID)((UINT_PTR)FileHeader + pidhDosHeader->e_lfanew);
+ }
+
+ /*
+ * the buffer doesn't contain the NT file header, or the alignment is wrong: we
+ * need to read the header from the file
+ */
+ if(FileHeaderSize < cbFileHeaderOffsetSize ||
+ (UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
+ {
+ ULONG cbNtHeaderSize;
+ ULONG cbReadSize;
+ PVOID pData;
+
+l_ReadHeaderFromFile:
+ cbNtHeaderSize = 0;
+ lnOffset.QuadPart = pidhDosHeader->e_lfanew;
+
+ /* read the header from the file */
+ nStatus = ReadFileCb(File, &lnOffset, sizeof(IMAGE_NT_HEADERS64), &pData, &pBuffer, &cbReadSize);
+
+ if(!NT_SUCCESS(nStatus))
+ DIE(("ReadFile failed, status %08X\n", nStatus));
+
+ ASSERT(pData);
+ ASSERT(pBuffer);
+ ASSERT(cbReadSize > 0);
+
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ /* the buffer doesn't contain the file header */
+ if(cbReadSize < RTL_SIZEOF_THROUGH_FIELD(IMAGE_NT_HEADERS32, FileHeader))
+ DIE(("The file doesn't contain the PE file header\n"));
+
+ pinhNtHeader = pData;
+
+ /* object still not aligned: copy it to the beginning of the buffer */
+ if((UINT_PTR)pinhNtHeader % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) != 0)
+ {
+ ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_NT_HEADERS32) == 0);
+ RtlMoveMemory(pBuffer, pData, cbReadSize);
+ pinhNtHeader = pBuffer;
+ }
+
+ /* invalid NT header */
+ nStatus = STATUS_INVALID_IMAGE_PROTECT;
+
+ if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
+ DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
+
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ if(!Intsafe_AddULong32(&cbNtHeaderSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
+ DIE(("The full NT header is too large\n"));
+
+ /* the buffer doesn't contain the whole NT header */
+ if(cbReadSize < cbNtHeaderSize)
+ DIE(("The file doesn't contain the full NT header\n"));
+ }
+ else
+ {
+ ULONG cbOptHeaderOffsetSize = 0;
+
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ /* don't trust an invalid NT header */
+ if(pinhNtHeader->Signature != IMAGE_NT_SIGNATURE)
+ DIE(("The file isn't a PE executable, Signature is %X\n", pinhNtHeader->Signature));
+
+ if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
+ DIE(("The DOS stub is too large, e_lfanew is %X\n", pidhDosHeader->e_lfanew));
+
+ if(!Intsafe_AddULong32(&cbOptHeaderOffsetSize, cbOptHeaderOffsetSize, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
+ DIE(("The NT header is too large, SizeOfOptionalHeader is %X\n", pinhNtHeader->FileHeader.SizeOfOptionalHeader));
+
+ /* the buffer doesn't contain the whole NT header: read it from the file */
+ if(cbOptHeaderOffsetSize > FileHeaderSize)
+ goto l_ReadHeaderFromFile;
+ }
+
+ /* read information from the NT header */
+ piohOptHeader = &pinhNtHeader->OptionalHeader;
+ cbOptHeaderSize = pinhNtHeader->FileHeader.SizeOfOptionalHeader;
+
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ if(!RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Magic))
+ DIE(("The optional header doesn't contain the Magic field, SizeOfOptionalHeader is %X\n", cbOptHeaderSize));
+
+ /* ASSUME: RtlZeroMemory(ImageSectionObject, sizeof(*ImageSectionObject)); */
+
+ switch(piohOptHeader->Magic)
+ {
+ case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ break;
+
+ default:
+ DIE(("Unrecognized optional header, Magic is %X\n", piohOptHeader->Magic));
+ }
+
+ if (RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SectionAlignment) &&
+ RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, FileAlignment))
+ {
+ /* See [1], section 3.4.2 */
+ if(piohOptHeader->SectionAlignment < PAGE_SIZE)
+ {
+ if(piohOptHeader->FileAlignment != piohOptHeader->SectionAlignment)
+ DIE(("Sections aren't page-aligned and the file alignment isn't the same\n"));
+ }
+ else if(piohOptHeader->SectionAlignment < piohOptHeader->FileAlignment)
+ DIE(("The section alignment is smaller than the file alignment\n"));
+
+ nSectionAlignment = piohOptHeader->SectionAlignment;
+ nFileAlignment = piohOptHeader->FileAlignment;
+
+ if(!IsPowerOf2(nSectionAlignment) || !IsPowerOf2(nFileAlignment))
+ DIE(("The section alignment (%u) and file alignment (%u) aren't both powers of 2\n", nSectionAlignment, nFileAlignment));
+ }
+ else
+ {
+ nSectionAlignment = PAGE_SIZE;
+ nFileAlignment = PAGE_SIZE;
+ }
+
+ ASSERT(IsPowerOf2(nSectionAlignment));
+ ASSERT(IsPowerOf2(nFileAlignment));
+
+ switch(piohOptHeader->Magic)
+ {
+ /* PE32 */
+ case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ {
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, ImageBase))
+ ImageSectionObject->ImageBase = piohOptHeader->ImageBase;
+
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfImage))
+ ImageSectionObject->ImageSize = piohOptHeader->SizeOfImage;
+
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackReserve))
+ ImageSectionObject->StackReserve = piohOptHeader->SizeOfStackReserve;
+
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfStackCommit))
+ ImageSectionObject->StackCommit = piohOptHeader->SizeOfStackCommit;
+
+ break;
+ }
+
+ /* PE32+ */
+ case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ {
+ const IMAGE_OPTIONAL_HEADER64 * pioh64OptHeader;
+
+ pioh64OptHeader = (const IMAGE_OPTIONAL_HEADER64 *)piohOptHeader;
+
+ if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, ImageBase))
+ {
+ if(pioh64OptHeader->ImageBase > MAXULONG_PTR)
+ DIE(("ImageBase exceeds the address space\n"));
+
+ ImageSectionObject->ImageBase = (ULONG_PTR)pioh64OptHeader->ImageBase;
+ }
+
+ if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfImage))
+ {
+ if(pioh64OptHeader->SizeOfImage > MAXULONG_PTR)
+ DIE(("SizeOfImage exceeds the address space\n"));
+
+ ImageSectionObject->ImageSize = pioh64OptHeader->SizeOfImage;
+ }
+
+ if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackReserve))
+ {
+ if(pioh64OptHeader->SizeOfStackReserve > MAXULONG_PTR)
+ DIE(("SizeOfStackReserve exceeds the address space\n"));
+
+ ImageSectionObject->StackReserve = pioh64OptHeader->SizeOfStackReserve;
+ }
+
+ if(RTL_CONTAINS_FIELD(pioh64OptHeader, cbOptHeaderSize, SizeOfStackCommit))
+ {
+ if(pioh64OptHeader->SizeOfStackCommit > MAXULONG_PTR)
+ DIE(("SizeOfStackCommit exceeds the address space\n"));
+
+ ImageSectionObject->StackCommit = pioh64OptHeader->SizeOfStackCommit;
+ }
+
+ break;
+ }
+ }
+
+ /* [1], section 3.4.2 */
+ if((ULONG_PTR)ImageSectionObject->ImageBase % 0x10000)
+ DIE(("ImageBase is not aligned on a 64KB boundary"));
+
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, Subsystem))
+ {
+ ImageSectionObject->Subsystem = piohOptHeader->Subsystem;
+
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MinorSubsystemVersion) &&
+ RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, MajorSubsystemVersion))
+ {
+ ImageSectionObject->MinorSubsystemVersion = piohOptHeader->MinorSubsystemVersion;
+ ImageSectionObject->MajorSubsystemVersion = piohOptHeader->MajorSubsystemVersion;
+ }
+ }
+
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
+ {
+ ImageSectionObject->EntryPoint = piohOptHeader->ImageBase +
+ piohOptHeader->AddressOfEntryPoint;
+ }
+
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfCode))
+ ImageSectionObject->Executable = piohOptHeader->SizeOfCode != 0;
+ else
+ ImageSectionObject->Executable = TRUE;
+
+ ImageSectionObject->ImageCharacteristics = pinhNtHeader->FileHeader.Characteristics;
+ ImageSectionObject->Machine = pinhNtHeader->FileHeader.Machine;
+
+ /* SECTION HEADERS */
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ /* see [1], section 3.3 */
+ if(pinhNtHeader->FileHeader.NumberOfSections > 96)
+ DIE(("Too many sections, NumberOfSections is %u\n", pinhNtHeader->FileHeader.NumberOfSections));
+
+ /*
+ * the additional segment is for the file's headers. They need to be present for
+ * the benefit of the dynamic loader (to locate exports, defaults for thread
+ * parameters, resources, etc.)
+ */
+ ImageSectionObject->NrSegments = pinhNtHeader->FileHeader.NumberOfSections + 1;
+
+ /* file offset for the section headers */
+ if(!Intsafe_AddULong32(&cbSectionHeadersOffset, pidhDosHeader->e_lfanew, FIELD_OFFSET(IMAGE_NT_HEADERS32, OptionalHeader)))
+ DIE(("Offset overflow\n"));
+
+ if(!Intsafe_AddULong32(&cbSectionHeadersOffset, cbSectionHeadersOffset, pinhNtHeader->FileHeader.SizeOfOptionalHeader))
+ DIE(("Offset overflow\n"));
+
+ /* size of the section headers */
+ ASSERT(Intsafe_CanMulULong32(pinhNtHeader->FileHeader.NumberOfSections, sizeof(IMAGE_SECTION_HEADER)));
+ cbSectionHeadersSize = pinhNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
+
+ if(!Intsafe_AddULong32(&cbSectionHeadersOffsetSize, cbSectionHeadersOffset, cbSectionHeadersSize))
+ DIE(("Section headers too large\n"));
+
+ /* size of the executable's headers */
+ if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, SizeOfHeaders))
+ {
+// if(!IsAligned(piohOptHeader->SizeOfHeaders, nFileAlignment))
+// DIE(("SizeOfHeaders is not aligned\n"));
+
+ if(cbSectionHeadersSize > piohOptHeader->SizeOfHeaders)
+ DIE(("The section headers overflow SizeOfHeaders\n"));
+
+ cbHeadersSize = piohOptHeader->SizeOfHeaders;
+ }
+ else if(!AlignUp(&cbHeadersSize, cbSectionHeadersOffsetSize, nFileAlignment))
+ DIE(("Overflow aligning the size of headers\n"));
+
+ if(pBuffer)
+ {
+ ExFreePool(pBuffer);
+ pBuffer = NULL;
+ }
+ /* WARNING: pinhNtHeader IS NO LONGER USABLE */
+ /* WARNING: piohOptHeader IS NO LONGER USABLE */
+ /* WARNING: pioh64OptHeader IS NO LONGER USABLE */
+
+ if(FileHeaderSize < cbSectionHeadersOffsetSize)
+ pishSectionHeaders = NULL;
+ else
+ {
+ /*
+ * we already know that Intsafe_CanOffsetPointer(FileHeader, FileHeaderSize),
+ * and FileHeaderSize >= cbSectionHeadersOffsetSize, so this holds true too
+ */
+ ASSERT(Intsafe_CanOffsetPointer(FileHeader, cbSectionHeadersOffset));
+ pishSectionHeaders = (PVOID)((UINT_PTR)FileHeader + cbSectionHeadersOffset);
+ }
+
+ /*
+ * the buffer doesn't contain the section headers, or the alignment is wrong:
+ * read the headers from the file
+ */
+ if(FileHeaderSize < cbSectionHeadersOffsetSize ||
+ (UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
+ {
+ PVOID pData;
+ ULONG cbReadSize;
+
+ lnOffset.QuadPart = cbSectionHeadersOffset;
+
+ /* read the header from the file */
+ nStatus = ReadFileCb(File, &lnOffset, cbSectionHeadersSize, &pData, &pBuffer, &cbReadSize);
+
+ if(!NT_SUCCESS(nStatus))
+ DIE(("ReadFile failed with status %08X\n", nStatus));
+
+ ASSERT(pData);
+ ASSERT(pBuffer);
+ ASSERT(cbReadSize > 0);
+
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ /* the buffer doesn't contain all the section headers */
+ if(cbReadSize < cbSectionHeadersSize)
+ DIE(("The file doesn't contain all of the section headers\n"));
+
+ pishSectionHeaders = pData;
+
+ /* object still not aligned: copy it to the beginning of the buffer */
+ if((UINT_PTR)pishSectionHeaders % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) != 0)
+ {
+ ASSERT((UINT_PTR)pBuffer % TYPE_ALIGNMENT(IMAGE_SECTION_HEADER) == 0);
+ RtlMoveMemory(pBuffer, pData, cbReadSize);
+ pishSectionHeaders = pBuffer;
+ }
+ }
+
+ /* SEGMENTS */
+ /* allocate the segments */
+ nStatus = STATUS_INSUFFICIENT_RESOURCES;
+ ImageSectionObject->Segments = AllocateSegmentsCb(ImageSectionObject->NrSegments);
+
+ if(ImageSectionObject->Segments == NULL)
+ DIE(("AllocateSegments failed\n"));
+
+ /* initialize the headers segment */
+ pssSegments = ImageSectionObject->Segments;
+
+// ASSERT(IsAligned(cbHeadersSize, nFileAlignment));
+
+ if(!AlignUp(&nFileSizeOfHeaders, cbHeadersSize, nFileAlignment))
+ DIE(("Cannot align the size of the section headers\n"));
+
+ if(!AlignUp(&nPrevVirtualEndOfSegment, cbHeadersSize, nSectionAlignment))
+ DIE(("Cannot align the size of the section headers\n"));
+
+ pssSegments[0].FileOffset = 0;
+ pssSegments[0].Protection = PAGE_READONLY;
+ pssSegments[0].Length = nPrevVirtualEndOfSegment;
+ pssSegments[0].RawLength = nFileSizeOfHeaders;
+ pssSegments[0].VirtualAddress = 0;
+ pssSegments[0].Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA;
+ pssSegments[0].WriteCopy = TRUE;
+
+ /* skip the headers segment */
+ ++ pssSegments;
+
+ nStatus = STATUS_INVALID_IMAGE_FORMAT;
+
+ /* convert the executable sections into segments. See also [1], section 4 */
+ for(i = 0; i < ImageSectionObject->NrSegments - 1; ++ i)
+ {
+ ULONG nCharacteristics;
+
+ /* validate the alignment */
+ if(!IsAligned(pishSectionHeaders[i].VirtualAddress, nSectionAlignment))
+ DIE(("VirtualAddress[%u] is not aligned\n", i));
+
+ /* sections must be contiguous, ordered by base address and non-overlapping */
+ if(pishSectionHeaders[i].VirtualAddress != nPrevVirtualEndOfSegment)
+ DIE(("Memory gap between section %u and the previous\n", i));
+
+ /* ignore explicit BSS sections */
+ if(pishSectionHeaders[i].SizeOfRawData != 0)
+ {
+ /* validate the alignment */
+#if 0
+ /* Yes, this should be a multiple of FileAlignment, but there's
+ * stuff out there that isn't. We can cope with that
+ */
+ if(!IsAligned(pishSectionHeaders[i].SizeOfRawData, nFileAlignment))
+ DIE(("SizeOfRawData[%u] is not aligned\n", i));
#endif
- if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
- DIE(("PointerToRawData[%u] is not aligned\n", i));
+// if(!IsAligned(pishSectionHeaders[i].PointerToRawData, nFileAlignment))
+// DIE(("PointerToRawData[%u] is not aligned\n", i));
- /* conversion */
- pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData;
- pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
- }
- else
- {
- ASSERT(pssSegments[i].FileOffset == 0);
- ASSERT(pssSegments[i].RawLength == 0);
- }
+ /* conversion */
+ pssSegments[i].FileOffset = pishSectionHeaders[i].PointerToRawData;
+ pssSegments[i].RawLength = pishSectionHeaders[i].SizeOfRawData;
+ }
+ else
+ {
+ ASSERT(pssSegments[i].FileOffset == 0);
+ ASSERT(pssSegments[i].RawLength == 0);
+ }
- ASSERT(Intsafe_CanAddLong64(pssSegments[i].FileOffset, pssSegments[i].RawLength));
+ ASSERT(Intsafe_CanAddLong64(pssSegments[i].FileOffset, pssSegments[i].RawLength));
- nCharacteristics = pishSectionHeaders[i].Characteristics;
+ nCharacteristics = pishSectionHeaders[i].Characteristics;
- /* no explicit protection */
- if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
- {
- if(nCharacteristics & IMAGE_SCN_CNT_CODE)
- nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
+ /* no explicit protection */
+ if((nCharacteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)) == 0)
+ {
+ if(nCharacteristics & IMAGE_SCN_CNT_CODE)
+ nCharacteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
- if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
- nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
+ if(nCharacteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
- if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
- nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
- }
+ if(nCharacteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ nCharacteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
+ }
- /* see table above */
- pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
- pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
+ /* see table above */
+ pssSegments[i].Protection = SectionCharacteristicsToProtect[nCharacteristics >> 28];
+ pssSegments[i].WriteCopy = !(nCharacteristics & IMAGE_SCN_MEM_SHARED);
- if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
- pssSegments[i].Length = pishSectionHeaders[i].SizeOfRawData;
- else
- pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
+ if(pishSectionHeaders[i].Misc.VirtualSize == 0 || pishSectionHeaders[i].Misc.VirtualSize < pishSectionHeaders[i].SizeOfRawData)
+ pssSegments[i].Length = pishSectionHeaders[i].SizeOfRawData;
+ else
+ pssSegments[i].Length = pishSectionHeaders[i].Misc.VirtualSize;
- if(!AlignUp(&pssSegments[i].Length, pssSegments[i].Length, nSectionAlignment))
- DIE(("Cannot align the virtual size of section %u\n", i));
+ if(!AlignUp(&pssSegments[i].Length, pssSegments[i].Length, nSectionAlignment))
+ DIE(("Cannot align the virtual size of section %u\n", i));
- ASSERT(IsAligned(pssSegments[i].Length, nSectionAlignment));
+ ASSERT(IsAligned(pssSegments[i].Length, nSectionAlignment));
- if(pssSegments[i].Length == 0)
- DIE(("Virtual size of section %u is null\n", i));
+ if(pssSegments[i].Length == 0)
+ DIE(("Virtual size of section %u is null\n", i));
- pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress;
- pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics;
+ pssSegments[i].VirtualAddress = pishSectionHeaders[i].VirtualAddress;
+ pssSegments[i].Characteristics = pishSectionHeaders[i].Characteristics;
- /* ensure the memory image is no larger than 4GB */
- if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[i].VirtualAddress, pssSegments[i].Length))
- DIE(("The image is larger than 4GB\n"));
- }
+ /* ensure the memory image is no larger than 4GB */
+ if(!Intsafe_AddULong32(&nPrevVirtualEndOfSegment, pssSegments[i].VirtualAddress, pssSegments[i].Length))
+ DIE(("The image is larger than 4GB\n"));
+ }
- /* spare our caller some work in validating the segments */
- *Flags = EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP;
+ /* spare our caller some work in validating the segments */
+ *Flags = EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED | EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP;
- if(nSectionAlignment >= PAGE_SIZE)
- *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
+ if(nSectionAlignment >= PAGE_SIZE)
+ *Flags |= EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED;
- /* Success */
- nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT & EXEFMT_LOADED_PE32;
+ /* Success */
+ nStatus = STATUS_ROS_EXEFMT_LOADED_FORMAT | EXEFMT_LOADED_PE32;
l_Return:
- if(pBuffer)
- ExFreePool(pBuffer);
+ if(pBuffer)
+ ExFreePool(pBuffer);
- return nStatus;
+ return nStatus;
}
/* EOF */