[BOOTLIB]: Begin PE loader. Works so far. Next up is loading the sections, zeroing out the .bss, and computing checksum.

svn path=/trunk/; revision=70629
This commit is contained in:
Alex Ionescu 2016-01-20 17:00:18 +00:00
parent 26f25f68f5
commit 53c32a9428
2 changed files with 238 additions and 15 deletions

View file

@ -148,6 +148,13 @@ DEFINE_GUID(BadMemoryGuid, 0x54B8275B, 0xD431, 0x473F, 0xAC, 0xFB, 0xE5, 0x36, 0
#define BL_LOAD_IMG_COMPUTE_SIGNATURE 0x10
#define BL_LOAD_IMG_COMPUTE_HASH 0x40000
#define BL_LOAD_PE_IMG_VIRTUAL_BUFFER BL_LOAD_IMG_VIRTUAL_BUFFER
#define BL_LOAD_PE_IMG_CHECK_MACHINE 0x02
#define BL_LOAD_PE_IMG_EXISTING_BUFFER BL_LOAD_IMG_EXISTING_BUFFER
#define BL_LOAD_PE_IMG_COMPUTE_HASH 0x10
#define BL_LOAD_PE_IMG_CHECK_SUBSYSTEM 0x80
#define BL_LOAD_PE_IMG_CHECK_FORCED_INTEGRITY 0x200
/* ENUMERATIONS **************************************************************/
typedef enum _BL_COLOR

View file

@ -655,15 +655,240 @@ NTSTATUS
ImgpLoadPEImage (
_In_ PBL_IMG_FILE ImageFile,
_In_ BL_MEMORY_TYPE MemoryType,
_Out_ PVOID* ImageBase,
_Inout_ PVOID* ImageBase,
_Out_ PULONG ImageSize,
_Out_ PVOID Hash,
_Inout_opt_ PVOID Hash,
_In_ ULONG Flags
)
{
/* Micro-PE loader (no imports/exports/etc) */
EfiPrintf(L"PE not implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
NTSTATUS Status;
ULONG FileSize, HeaderSize;
PVOID ImageBuffer;
BL_IMG_FILE LocalFileBuffer;
PBL_IMG_FILE LocalFile;
PVOID VirtualAddress;
ULONGLONG VirtualSize;
PHYSICAL_ADDRESS PhysicalAddress;
PIMAGE_NT_HEADERS NtHeaders;
/* Initialize locals */
LocalFile = NULL;
ImageBuffer = NULL;
FileSize = 0;
/* Get the size of the image */
Status = ImgpGetFileSize(ImageFile, &FileSize);
if (!NT_SUCCESS(Status))
{
return STATUS_FILE_INVALID;
}
/* Allocate a flat buffer for it */
Status = BlImgAllocateImageBuffer(&ImageBuffer, BlLoaderData, FileSize, 0);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Read the whole file flat for now */
Status = ImgpReadAtFileOffset(ImageFile, FileSize, 0, ImageBuffer, NULL);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Build a local file handle */
LocalFile = &LocalFileBuffer;
LocalFileBuffer.FileName = ImageFile->FileName;
LocalFileBuffer.Flags = BL_IMG_MEMORY_FILE | BL_IMG_VALID_FILE;
LocalFileBuffer.BaseAddress = ImageBuffer;
LocalFileBuffer.FileSize = FileSize;
/* Get the NT headers of the file */
Status = RtlImageNtHeaderEx(0, ImageBuffer, FileSize, &NtHeaders);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Check if we should validate the machine type */
if (Flags & BL_LOAD_PE_IMG_CHECK_MACHINE)
{
/* Is it different than our current machine type? */
#if _M_AMD64
if (NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64)
#else
if (NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
#endif
{
/* Is it x86 (implying we are x64) ? */
if (NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
{
/* Return special error code */
Status = STATUS_INVALID_IMAGE_WIN_32;
}
else if (NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
{
/* Otherwise, it's x64 but we are x86 */
Status = STATUS_INVALID_IMAGE_WIN_64;
}
else
{
/* Or it's ARM or something... */
Status = STATUS_INVALID_IMAGE_FORMAT;
}
/* Return with the distinguished error code */
goto Quickie;
}
}
/* Check if we should validate the subsystem */
if (Flags & BL_LOAD_PE_IMG_CHECK_SUBSYSTEM)
{
/* It must be a Windows boot Application */
if (NtHeaders->OptionalHeader.Subsystem !=
IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
{
Status = STATUS_INVALID_IMAGE_FORMAT;
goto Quickie;
}
}
/* Check if we should validate the /INTEGRITYCHECK flag */
if (Flags & BL_LOAD_PE_IMG_CHECK_FORCED_INTEGRITY)
{
/* Check if it's there */
if (!(NtHeaders->OptionalHeader.DllCharacteristics &
IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY))
{
/* Nope, fail otherwise */
Status = STATUS_INVALID_IMAGE_FORMAT;
goto Quickie;
}
}
/* Check if we should compute the image hash */
if ((Flags & BL_LOAD_PE_IMG_COMPUTE_HASH) || (Hash))
{
EfiPrintf(L"No hash support\r\n");
}
/* Read the current base address, if any */
VirtualAddress = *ImageBase;
/* Get the virtual size of the image */
VirtualSize = NtHeaders->OptionalHeader.SizeOfImage;
/* Safely align the virtual size to a page */
Status = RtlULongLongAdd(VirtualSize,
PAGE_SIZE - 1,
&VirtualSize);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
VirtualSize = ALIGN_DOWN_BY(VirtualSize, PAGE_SIZE);
/* Make sure the image isn't larger than 4GB */
if (VirtualSize > ULONG_MAX)
{
Status = STATUS_INVALID_IMAGE_FORMAT;
goto Quickie;
}
/* Check if we have a buffer already */
if (Flags & BL_LOAD_IMG_EXISTING_BUFFER)
{
/* Check if it's too small */
if (*ImageSize < VirtualSize)
{
/* Fail, letting the caller know how big to make it */
*ImageSize = VirtualSize;
Status = STATUS_BUFFER_TOO_SMALL;
}
}
else
{
/* Allocate the buffer with the flags and type the caller wants */
Status = BlImgAllocateImageBuffer(&VirtualAddress,
MemoryType,
VirtualSize,
Flags);
}
/* Bail out if allocation failed, or existing buffer is too small */
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Read the size of the headers */
HeaderSize = NtHeaders->OptionalHeader.SizeOfHeaders;
if (VirtualSize < HeaderSize)
{
/* Bail out if they're bigger than the image! */
Status = STATUS_INVALID_IMAGE_FORMAT;
goto Quickie;
}
/* Now read the header into the buffer */
Status = ImgpReadAtFileOffset(LocalFile, HeaderSize, 0, VirtualAddress, NULL);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Get the NT headers of the file */
Status = RtlImageNtHeaderEx(0, VirtualAddress, HeaderSize, &NtHeaders);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
EfiPrintf(L"MORE PE TODO: %lx\r\n", NtHeaders->OptionalHeader.AddressOfEntryPoint);
EfiStall(100000000);
Quickie:
/* Check if we had an image buffer allocated */
if ((ImageBuffer) && (FileSize))
{
/* Free it */
BlImgUnallocateImageBuffer(ImageBuffer, FileSize, 0);
}
/* Check if we had a local file handle */
if (LocalFile)
{
/* Close it */
ImgpCloseFile(LocalFile);
}
/* Check if this is the failure path */
if (!NT_SUCCESS(Status))
{
/* Check if we had started mapping in the image already */
if ((VirtualAddress) && !(Flags & BL_LOAD_PE_IMG_EXISTING_BUFFER))
{
/* Into a virtual buffer? */
if (Flags & BL_LOAD_PE_IMG_VIRTUAL_BUFFER)
{
/* Unmap and free it */
BlMmUnmapVirtualAddressEx(VirtualAddress, VirtualSize);
PhysicalAddress.QuadPart = (ULONG_PTR)VirtualAddress;
BlMmFreePhysicalPages(PhysicalAddress);
}
else
{
/* Into a physical buffer -- free it */
EfiPrintf(L"Leaking physical pages\r\n");
// MmPapFreePages(VirtualAddress, TRUE);
}
}
}
/* Return back to caller */
return Status;
}
NTSTATUS
@ -691,7 +916,7 @@ BlImgLoadPEImageEx (
}
/* If we are loading a pre-allocated image, make sure we have it */
if ((Flags & 4) && (!(*ImageBase) || !(ImageSize)))
if ((Flags & BL_LOAD_IMG_EXISTING_BUFFER) && (!(*ImageBase) || !(ImageSize)))
{
return STATUS_INVALID_PARAMETER;
}
@ -708,11 +933,6 @@ BlImgLoadPEImageEx (
Hash,
Flags);
}
else
{
/* For temporary debugging */
EfiPrintf(L"Couldn't open file: %lx\r\n", Status);
}
/* Close the image file and return back to caller */
ImgpCloseFile(&ImageFile);
@ -750,8 +970,6 @@ BlImgLoadBootApplication (
ImageSize = 0;
ImageBase = NULL;
EfiPrintf(L"Loading application %p\r\n", BootEntry);
/* Check for "allowed in-memory settings" */
Status = BlpGetBootOptionIntegerList(BootEntry->BcdData,
BcdLibraryIntegerList_AllowedInMemorySettings,
@ -804,12 +1022,10 @@ BlImgLoadBootApplication (
}
/* Open the device */
EfiPrintf(L"Opening device for path: %s\r\n", Path);
Status = BlpDeviceOpen(Device,
BL_DEVICE_READ_ACCESS,
0,
&DeviceId);
EfiPrintf(L"Device ID: %lx %lx\r\n", Status, DeviceId);
if (!NT_SUCCESS(Status))
{
goto Quickie;