summaryrefslogtreecommitdiffstats
path: root/src/shared/pe-binary.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:49:52 +0000
commit55944e5e40b1be2afc4855d8d2baf4b73d1876b5 (patch)
tree33f869f55a1b149e9b7c2b7e201867ca5dd52992 /src/shared/pe-binary.h
parentInitial commit. (diff)
downloadsystemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.tar.xz
systemd-55944e5e40b1be2afc4855d8d2baf4b73d1876b5.zip
Adding upstream version 255.4.upstream/255.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/shared/pe-binary.h')
-rw-r--r--src/shared/pe-binary.h144
1 files changed, 144 insertions, 0 deletions
diff --git a/src/shared/pe-binary.h b/src/shared/pe-binary.h
new file mode 100644
index 0000000..2ef44d7
--- /dev/null
+++ b/src/shared/pe-binary.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <sys/types.h>
+
+#include "sparse-endian.h"
+
+/* When naming things we try to stay close to the official Windows APIs as per:
+ * → https://learn.microsoft.com/en-us/windows/win32/debug/pe-format */
+
+typedef struct _packed_ _IMAGE_DOS_HEADER {
+ le16_t e_magic;
+ le16_t e_cblp;
+ le16_t e_cp;
+ le16_t e_crlc;
+ le16_t e_cparhdr;
+ le16_t e_minalloc;
+ le16_t e_maxalloc;
+ le16_t e_ss;
+ le16_t e_sp;
+ le16_t e_csum;
+ le16_t e_ip;
+ le16_t e_cs;
+ le16_t e_lfarlc;
+ le16_t e_ovno;
+ le16_t e_res[4];
+ le16_t e_oemid;
+ le16_t e_oeminfo;
+ le16_t e_res2[10];
+ le32_t e_lfanew;
+} IMAGE_DOS_HEADER;
+
+typedef struct _packed_ _IMAGE_FILE_HEADER {
+ le16_t Machine;
+ le16_t NumberOfSections;
+ le32_t TimeDateStamp;
+ le32_t PointerToSymbolTable;
+ le32_t NumberOfSymbols;
+ le16_t SizeOfOptionalHeader;
+ le16_t Characteristics;
+} IMAGE_FILE_HEADER;
+
+typedef struct _packed_ _IMAGE_DATA_DIRECTORY {
+ le32_t VirtualAddress;
+ le32_t Size;
+} IMAGE_DATA_DIRECTORY;
+
+typedef struct _packed_ _IMAGE_OPTIONAL_HEADER {
+ /* Standard fields */
+ le16_t Magic;
+ uint8_t MajorLinkerVersion;
+ uint8_t MinorLinkerVersion;
+ le32_t SizeOfCode;
+ le32_t SizeOfInitializedData;
+ le32_t SizeOfUninitializedData;
+ le32_t AddressOfEntryPoint;
+ le32_t BaseOfCode;
+
+ /* Here the PE32 and PE32+ headers differ: PE32+ has one 64bit field, PE32+ has two 32bit fields */
+ union {
+ struct {
+ le32_t BaseOfData;
+ le32_t pe32_ImageBase;
+ };
+ le64_t pe32plus_ImageBase;
+ };
+
+ /* Additional fields */
+ le32_t SectionAlignment;
+ le32_t FileAlignment;
+ le16_t MajorOperatingSystemVersion;
+ le16_t MinorOperatingSystemVersion;
+ le16_t MajorImageVersion;
+ le16_t MinorImageVersion;
+ le16_t MajorSubsystemVersion;
+ le16_t MinorSubsystemVersion;
+ le32_t Win32VersionValue;
+ le32_t SizeOfImage;
+ le32_t SizeOfHeaders;
+ le32_t CheckSum;
+ le16_t Subsystem;
+ le16_t DllCharacteristics;
+
+ /* Here similar: on PE32+ some fields are 64bit that are 32bit on PE32. */
+ union {
+ struct {
+ le32_t pe32_SizeOfStackReserve;
+ le32_t pe32_SizeOfStackCommit;
+ le32_t pe32_SizeOfHeapReserve;
+ le32_t pe32_SizeOfHeapCommit;
+ le32_t pe32_LoaderFlags;
+ le32_t pe32_NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY pe32_DataDirectory[];
+ };
+ struct {
+ le64_t pe32plus_SizeOfStackReserve;
+ le64_t pe32plus_SizeOfStackCommit;
+ le64_t pe32plus_SizeOfHeapReserve;
+ le64_t pe32plus_SizeOfHeapCommit;
+ le32_t pe32plus_LoaderFlags;
+ le32_t pe32plus_NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY pe32plus_DataDirectory[];
+ };
+ };
+} IMAGE_OPTIONAL_HEADER;
+
+typedef struct _packed_ PeHeader {
+ le32_t signature;
+ IMAGE_FILE_HEADER pe;
+ IMAGE_OPTIONAL_HEADER optional;
+} PeHeader;
+
+typedef struct _packed_ _IMAGE_SECTION_HEADER {
+ uint8_t Name[8];
+ le32_t VirtualSize;
+ le32_t VirtualAddress;
+ le32_t SizeOfRawData;
+ le32_t PointerToRawData;
+ le32_t PointerToRelocations;
+ le32_t PointerToLinenumbers;
+ le16_t NumberOfRelocations;
+ le16_t NumberOfLinenumbers;
+ le32_t Characteristics;
+} IMAGE_SECTION_HEADER;
+
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
+
+bool pe_header_is_64bit(const PeHeader *h);
+
+#define PE_HEADER_OPTIONAL_FIELD(h, field) \
+ (pe_header_is_64bit(h) ? (h)->optional.pe32plus_##field : (h)->optional.pe32_##field)
+
+#define PE_HEADER_OPTIONAL_FIELD_OFFSET(h, field) \
+ (pe_header_is_64bit(h) ? offsetof(PeHeader, optional.pe32plus_##field) : offsetof(PeHeader, optional.pe32_##field))
+
+const IMAGE_DATA_DIRECTORY *pe_header_get_data_directory(const PeHeader *h, size_t i);
+const IMAGE_SECTION_HEADER *pe_header_find_section(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections, const char *name);
+
+int pe_load_headers(int fd, IMAGE_DOS_HEADER **ret_dos_header, PeHeader **ret_pe_header);
+
+int pe_load_sections(int fd, const IMAGE_DOS_HEADER *dos_header, const PeHeader *pe_header, IMAGE_SECTION_HEADER **ret_sections);
+int pe_read_section_data(int fd, const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections, const char *name, size_t max_size, void **ret, size_t *ret_size);
+
+bool pe_is_uki(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections);