2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2015-02-08 12:25:35 +01:00
|
|
|
/*
|
2018-06-12 17:15:23 +02:00
|
|
|
* Copyright © 2015 Kay Sievers <kay@vrfy.org>
|
2015-02-08 12:25:35 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <efi.h>
|
|
|
|
#include <efilib.h>
|
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
#include "pe.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "util.h"
|
2015-02-08 12:25:35 +01:00
|
|
|
|
|
|
|
struct DosFileHeader {
|
|
|
|
UINT8 Magic[2];
|
|
|
|
UINT16 LastSize;
|
|
|
|
UINT16 nBlocks;
|
|
|
|
UINT16 nReloc;
|
|
|
|
UINT16 HdrSize;
|
|
|
|
UINT16 MinAlloc;
|
|
|
|
UINT16 MaxAlloc;
|
|
|
|
UINT16 ss;
|
|
|
|
UINT16 sp;
|
|
|
|
UINT16 Checksum;
|
|
|
|
UINT16 ip;
|
|
|
|
UINT16 cs;
|
|
|
|
UINT16 RelocPos;
|
|
|
|
UINT16 nOverlay;
|
|
|
|
UINT16 reserved[4];
|
|
|
|
UINT16 OEMId;
|
|
|
|
UINT16 OEMInfo;
|
|
|
|
UINT16 reserved2[10];
|
|
|
|
UINT32 ExeHeader;
|
|
|
|
} __attribute__((packed));
|
|
|
|
|
|
|
|
#define PE_HEADER_MACHINE_I386 0x014c
|
|
|
|
#define PE_HEADER_MACHINE_X64 0x8664
|
|
|
|
struct PeFileHeader {
|
|
|
|
UINT16 Machine;
|
|
|
|
UINT16 NumberOfSections;
|
|
|
|
UINT32 TimeDateStamp;
|
|
|
|
UINT32 PointerToSymbolTable;
|
|
|
|
UINT32 NumberOfSymbols;
|
|
|
|
UINT16 SizeOfOptionalHeader;
|
|
|
|
UINT16 Characteristics;
|
|
|
|
} __attribute__((packed));
|
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
struct PeHeader {
|
|
|
|
UINT8 Magic[4];
|
|
|
|
struct PeFileHeader FileHeader;
|
|
|
|
} __attribute__((packed));
|
|
|
|
|
2015-02-08 12:25:35 +01:00
|
|
|
struct PeSectionHeader {
|
|
|
|
UINT8 Name[8];
|
|
|
|
UINT32 VirtualSize;
|
|
|
|
UINT32 VirtualAddress;
|
|
|
|
UINT32 SizeOfRawData;
|
|
|
|
UINT32 PointerToRawData;
|
|
|
|
UINT32 PointerToRelocations;
|
|
|
|
UINT32 PointerToLinenumbers;
|
|
|
|
UINT16 NumberOfRelocations;
|
|
|
|
UINT16 NumberOfLinenumbers;
|
|
|
|
UINT32 Characteristics;
|
|
|
|
} __attribute__((packed));
|
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
|
|
|
|
struct DosFileHeader *dos;
|
|
|
|
struct PeHeader *pe;
|
|
|
|
UINTN i;
|
|
|
|
UINTN offset;
|
|
|
|
|
|
|
|
dos = (struct DosFileHeader *)base;
|
|
|
|
|
|
|
|
if (CompareMem(dos->Magic, "MZ", 2) != 0)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
pe = (struct PeHeader *)&base[dos->ExeHeader];
|
|
|
|
if (CompareMem(pe->Magic, "PE\0\0", 4) != 0)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
/* PE32+ Subsystem type */
|
|
|
|
if (pe->FileHeader.Machine != PE_HEADER_MACHINE_X64 &&
|
|
|
|
pe->FileHeader.Machine != PE_HEADER_MACHINE_I386)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
if (pe->FileHeader.NumberOfSections > 96)
|
|
|
|
return EFI_LOAD_ERROR;
|
|
|
|
|
|
|
|
offset = dos->ExeHeader + sizeof(*pe) + pe->FileHeader.SizeOfOptionalHeader;
|
|
|
|
|
|
|
|
for (i = 0; i < pe->FileHeader.NumberOfSections; i++) {
|
|
|
|
struct PeSectionHeader *sect;
|
|
|
|
UINTN j;
|
|
|
|
|
|
|
|
sect = (struct PeSectionHeader *)&base[offset];
|
|
|
|
for (j = 0; sections[j]; j++) {
|
|
|
|
if (CompareMem(sect->Name, sections[j], strlena(sections[j])) != 0)
|
|
|
|
continue;
|
2015-02-08 12:25:35 +01:00
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
if (addrs)
|
|
|
|
addrs[j] = (UINTN)sect->VirtualAddress;
|
|
|
|
if (offsets)
|
|
|
|
offsets[j] = (UINTN)sect->PointerToRawData;
|
|
|
|
if (sizes)
|
|
|
|
sizes[j] = (UINTN)sect->VirtualSize;
|
|
|
|
}
|
|
|
|
offset += sizeof(*sect);
|
|
|
|
}
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) {
|
2015-02-08 12:25:35 +01:00
|
|
|
EFI_FILE_HANDLE handle;
|
|
|
|
struct DosFileHeader dos;
|
2017-06-30 20:27:47 +02:00
|
|
|
struct PeHeader pe;
|
2015-02-08 12:25:35 +01:00
|
|
|
UINTN len;
|
2017-06-30 20:27:47 +02:00
|
|
|
UINTN headerlen;
|
2015-02-08 12:25:35 +01:00
|
|
|
EFI_STATUS err;
|
2018-03-13 10:47:17 +01:00
|
|
|
_cleanup_freepool_ CHAR8 *header = NULL;
|
2015-02-08 12:25:35 +01:00
|
|
|
|
|
|
|
err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
|
|
|
|
if (EFI_ERROR(err))
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* MS-DOS stub */
|
|
|
|
len = sizeof(dos);
|
|
|
|
err = uefi_call_wrapper(handle->Read, 3, handle, &len, &dos);
|
|
|
|
if (EFI_ERROR(err))
|
|
|
|
goto out;
|
|
|
|
if (len != sizeof(dos)) {
|
|
|
|
err = EFI_LOAD_ERROR;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
err = uefi_call_wrapper(handle->SetPosition, 2, handle, dos.ExeHeader);
|
|
|
|
if (EFI_ERROR(err))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
len = sizeof(pe);
|
|
|
|
err = uefi_call_wrapper(handle->Read, 3, handle, &len, &pe);
|
|
|
|
if (EFI_ERROR(err))
|
|
|
|
goto out;
|
|
|
|
if (len != sizeof(pe)) {
|
|
|
|
err = EFI_LOAD_ERROR;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
headerlen = sizeof(dos) + sizeof(pe) + pe.FileHeader.SizeOfOptionalHeader + pe.FileHeader.NumberOfSections * sizeof(struct PeSectionHeader);
|
|
|
|
header = AllocatePool(headerlen);
|
|
|
|
if (!header) {
|
|
|
|
err = EFI_OUT_OF_RESOURCES;
|
2015-02-08 12:25:35 +01:00
|
|
|
goto out;
|
|
|
|
}
|
2017-06-30 20:27:47 +02:00
|
|
|
len = headerlen;
|
|
|
|
err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0);
|
|
|
|
if (EFI_ERROR(err))
|
|
|
|
goto out;
|
2015-02-08 12:25:35 +01:00
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
err = uefi_call_wrapper(handle->Read, 3, handle, &len, header);
|
2018-03-13 10:47:17 +01:00
|
|
|
if (EFI_ERROR(err))
|
2015-02-08 12:25:35 +01:00
|
|
|
goto out;
|
2018-03-13 10:47:17 +01:00
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
if (len != headerlen) {
|
|
|
|
err = EFI_LOAD_ERROR;
|
2015-02-08 12:25:35 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2017-06-30 20:27:47 +02:00
|
|
|
err = pe_memory_locate_sections(header, sections, addrs, offsets, sizes);
|
2015-02-08 12:25:35 +01:00
|
|
|
out:
|
|
|
|
uefi_call_wrapper(handle->Close, 1, handle);
|
|
|
|
return err;
|
|
|
|
}
|