summaryrefslogtreecommitdiffstats
path: root/src/shared/pe-binary.h
blob: 20f839e9a00b51118f357716293488ab5dd20274 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* 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);
const IMAGE_SECTION_HEADER *pe_section_table_find(const IMAGE_SECTION_HEADER *sections, size_t n_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 IMAGE_SECTION_HEADER *section, size_t max_size, void **ret, size_t *ret_size);
int pe_read_section_data_by_name(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);
bool pe_is_addon(const PeHeader *pe_header, const IMAGE_SECTION_HEADER *sections);