1839529caSEd Maste /*-
2839529caSEd Maste * Copyright (c) 2016 Kai Wang
3839529caSEd Maste * All rights reserved.
4839529caSEd Maste *
5839529caSEd Maste * Redistribution and use in source and binary forms, with or without
6839529caSEd Maste * modification, are permitted provided that the following conditions
7839529caSEd Maste * are met:
8839529caSEd Maste * 1. Redistributions of source code must retain the above copyright
9839529caSEd Maste * notice, this list of conditions and the following disclaimer.
10839529caSEd Maste * 2. Redistributions in binary form must reproduce the above copyright
11839529caSEd Maste * notice, this list of conditions and the following disclaimer in the
12839529caSEd Maste * documentation and/or other materials provided with the distribution.
13839529caSEd Maste *
14839529caSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15839529caSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16839529caSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17839529caSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18839529caSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19839529caSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20839529caSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21839529caSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22839529caSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23839529caSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24839529caSEd Maste * SUCH DAMAGE.
25839529caSEd Maste */
26839529caSEd Maste
27839529caSEd Maste #include <sys/param.h>
28839529caSEd Maste #include <err.h>
29839529caSEd Maste #include <gelf.h>
30839529caSEd Maste #include <libpe.h>
31839529caSEd Maste #include <stdlib.h>
32839529caSEd Maste #include <string.h>
33839529caSEd Maste #include <time.h>
34839529caSEd Maste
35839529caSEd Maste #include "elfcopy.h"
36839529caSEd Maste
37b6d812d2SEd Maste ELFTC_VCSID("$Id: pe.c 3508 2016-12-27 06:19:39Z kaiwang27 $");
38839529caSEd Maste
39839529caSEd Maste /* Convert ELF object to Portable Executable (PE). */
40839529caSEd Maste void
create_pe(struct elfcopy * ecp,int ifd,int ofd)41839529caSEd Maste create_pe(struct elfcopy *ecp, int ifd, int ofd)
42839529caSEd Maste {
43839529caSEd Maste Elf *e;
44839529caSEd Maste Elf_Scn *scn;
45839529caSEd Maste Elf_Data *d;
46839529caSEd Maste GElf_Ehdr eh;
47839529caSEd Maste GElf_Shdr sh;
48839529caSEd Maste PE *pe;
49839529caSEd Maste PE_Scn *ps;
50839529caSEd Maste PE_SecHdr psh;
51839529caSEd Maste PE_CoffHdr pch;
52839529caSEd Maste PE_OptHdr poh;
53839529caSEd Maste PE_Object po;
54839529caSEd Maste PE_Buffer *pb;
55839529caSEd Maste const char *name;
56839529caSEd Maste size_t indx;
57b6d812d2SEd Maste time_t timestamp;
58d38447b5SEd Maste int elferr;
59839529caSEd Maste
60839529caSEd Maste if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64)
61839529caSEd Maste po = PE_O_PE32P;
62839529caSEd Maste else
63839529caSEd Maste po = PE_O_PE32;
64839529caSEd Maste
65839529caSEd Maste if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
66839529caSEd Maste errx(EXIT_FAILURE, "elf_begin() failed: %s",
67839529caSEd Maste elf_errmsg(-1));
68839529caSEd Maste
69839529caSEd Maste if (gelf_getehdr(e, &eh) == NULL)
70839529caSEd Maste errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
71839529caSEd Maste elf_errmsg(-1));
72839529caSEd Maste
73d0aa5645SEd Maste if (elf_getshstrndx(e, &indx) == 0)
74839529caSEd Maste errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s",
75839529caSEd Maste elf_errmsg(-1));
76839529caSEd Maste
77839529caSEd Maste if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL)
78839529caSEd Maste err(EXIT_FAILURE, "pe_init() failed");
79839529caSEd Maste
80839529caSEd Maste /* Setup PE COFF header. */
81839529caSEd Maste memset(&pch, 0, sizeof(pch));
82839529caSEd Maste switch (ecp->oem) {
83839529caSEd Maste case EM_386:
84839529caSEd Maste pch.ch_machine = IMAGE_FILE_MACHINE_I386;
85839529caSEd Maste break;
86839529caSEd Maste case EM_X86_64:
87839529caSEd Maste pch.ch_machine = IMAGE_FILE_MACHINE_AMD64;
88839529caSEd Maste break;
89839529caSEd Maste default:
90839529caSEd Maste pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN;
91839529caSEd Maste break;
92839529caSEd Maste }
93b6d812d2SEd Maste if (elftc_timestamp(×tamp) != 0)
94b6d812d2SEd Maste err(EXIT_FAILURE, "elftc_timestamp");
95b6d812d2SEd Maste pch.ch_timestamp = (uint32_t) timestamp;
96839529caSEd Maste if (pe_update_coff_header(pe, &pch) < 0)
97839529caSEd Maste err(EXIT_FAILURE, "pe_update_coff_header() failed");
98839529caSEd Maste
99839529caSEd Maste /* Setup PE optional header. */
100839529caSEd Maste memset(&poh, 0, sizeof(poh));
101839529caSEd Maste if (ecp->otf == ETF_EFI)
102839529caSEd Maste poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
103839529caSEd Maste poh.oh_entry = (uint32_t) eh.e_entry;
104839529caSEd Maste
105839529caSEd Maste /*
106839529caSEd Maste * Default section alignment and file alignment. (Here the
107839529caSEd Maste * section alignment is set to the default page size of the
108839529caSEd Maste * archs supported. We should use different section alignment
109839529caSEd Maste * for some arch. (e.g. IA64)
110839529caSEd Maste */
111839529caSEd Maste poh.oh_secalign = 0x1000;
112839529caSEd Maste poh.oh_filealign = 0x200;
113839529caSEd Maste
114839529caSEd Maste /* Copy sections. */
115839529caSEd Maste scn = NULL;
116839529caSEd Maste while ((scn = elf_nextscn(e, scn)) != NULL) {
117839529caSEd Maste
118839529caSEd Maste /*
119839529caSEd Maste * Read in ELF section.
120839529caSEd Maste */
121839529caSEd Maste
122839529caSEd Maste if (gelf_getshdr(scn, &sh) == NULL) {
123839529caSEd Maste warnx("gelf_getshdr() failed: %s", elf_errmsg(-1));
124839529caSEd Maste (void) elf_errno();
125839529caSEd Maste continue;
126839529caSEd Maste }
127d0aa5645SEd Maste if ((name = elf_strptr(e, indx, sh.sh_name)) ==
128839529caSEd Maste NULL) {
129839529caSEd Maste warnx("elf_strptr() failed: %s", elf_errmsg(-1));
130839529caSEd Maste (void) elf_errno();
131839529caSEd Maste continue;
132839529caSEd Maste }
133839529caSEd Maste
134839529caSEd Maste /* Skip sections unneeded. */
135839529caSEd Maste if (strcmp(name, ".shstrtab") == 0 ||
136839529caSEd Maste strcmp(name, ".symtab") == 0 ||
137839529caSEd Maste strcmp(name, ".strtab") == 0)
138839529caSEd Maste continue;
139839529caSEd Maste
140839529caSEd Maste if ((d = elf_getdata(scn, NULL)) == NULL) {
141839529caSEd Maste warnx("elf_getdata() failed: %s", elf_errmsg(-1));
142839529caSEd Maste (void) elf_errno();
143839529caSEd Maste continue;
144839529caSEd Maste }
145839529caSEd Maste
146839529caSEd Maste if (strcmp(name, ".text") == 0) {
147839529caSEd Maste poh.oh_textbase = (uint32_t) sh.sh_addr;
148839529caSEd Maste poh.oh_textsize = (uint32_t) roundup(sh.sh_size,
149839529caSEd Maste poh.oh_filealign);
150839529caSEd Maste } else {
151839529caSEd Maste if (po == PE_O_PE32 && strcmp(name, ".data") == 0)
152839529caSEd Maste poh.oh_database = sh.sh_addr;
153839529caSEd Maste if (sh.sh_type == SHT_NOBITS)
154839529caSEd Maste poh.oh_bsssize += (uint32_t)
155839529caSEd Maste roundup(sh.sh_size, poh.oh_filealign);
156839529caSEd Maste else if (sh.sh_flags & SHF_ALLOC)
157839529caSEd Maste poh.oh_datasize += (uint32_t)
158839529caSEd Maste roundup(sh.sh_size, poh.oh_filealign);
159839529caSEd Maste }
160839529caSEd Maste
161839529caSEd Maste /*
162839529caSEd Maste * Create PE/COFF section.
163839529caSEd Maste */
164839529caSEd Maste
165839529caSEd Maste if ((ps = pe_newscn(pe)) == NULL) {
166839529caSEd Maste warn("pe_newscn() failed");
167839529caSEd Maste continue;
168839529caSEd Maste }
169839529caSEd Maste
170839529caSEd Maste /*
171839529caSEd Maste * Setup PE/COFF section header. The section name is not
172839529caSEd Maste * NUL-terminated if its length happens to be 8. Long
173839529caSEd Maste * section name should be truncated for PE image according
174839529caSEd Maste * to the PE/COFF specification.
175839529caSEd Maste */
176839529caSEd Maste memset(&psh, 0, sizeof(psh));
177839529caSEd Maste strncpy(psh.sh_name, name, sizeof(psh.sh_name));
178839529caSEd Maste psh.sh_addr = sh.sh_addr;
179839529caSEd Maste psh.sh_virtsize = sh.sh_size;
180839529caSEd Maste if (sh.sh_type != SHT_NOBITS)
181d38447b5SEd Maste psh.sh_rawsize = roundup(sh.sh_size, poh.oh_filealign);
182839529caSEd Maste else
183839529caSEd Maste psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
184839529caSEd Maste
185839529caSEd Maste /*
186839529caSEd Maste * Translate ELF section flags to PE/COFF section flags.
187839529caSEd Maste */
188839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_READ;
189839529caSEd Maste if (sh.sh_flags & SHF_WRITE)
190839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_WRITE;
191839529caSEd Maste if (sh.sh_flags & SHF_EXECINSTR)
192839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_EXECUTE |
193839529caSEd Maste IMAGE_SCN_CNT_CODE;
194839529caSEd Maste if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0)
195839529caSEd Maste psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA;
196839529caSEd Maste
197839529caSEd Maste /* Mark relocation section "discardable". */
198839529caSEd Maste if (strcmp(name, ".reloc") == 0)
199839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE;
200839529caSEd Maste
201839529caSEd Maste if (pe_update_section_header(ps, &psh) < 0) {
202839529caSEd Maste warn("pe_update_section_header() failed");
203839529caSEd Maste continue;
204839529caSEd Maste }
205839529caSEd Maste
206839529caSEd Maste /* Copy section content. */
207839529caSEd Maste if ((pb = pe_newbuffer(ps)) == NULL) {
208839529caSEd Maste warn("pe_newbuffer() failed");
209839529caSEd Maste continue;
210839529caSEd Maste }
211839529caSEd Maste pb->pb_align = 1;
212839529caSEd Maste pb->pb_off = 0;
213d0aa5645SEd Maste if (sh.sh_type != SHT_NOBITS) {
214d38447b5SEd Maste pb->pb_size = roundup(sh.sh_size, poh.oh_filealign);
215d38447b5SEd Maste if ((pb->pb_buf = calloc(1, pb->pb_size)) == NULL) {
216d38447b5SEd Maste warn("calloc failed");
217d38447b5SEd Maste continue;
218d38447b5SEd Maste }
219d38447b5SEd Maste memcpy(pb->pb_buf, d->d_buf, sh.sh_size);
220839529caSEd Maste }
221d0aa5645SEd Maste }
222839529caSEd Maste elferr = elf_errno();
223839529caSEd Maste if (elferr != 0)
224839529caSEd Maste warnx("elf_nextscn() failed: %s", elf_errmsg(elferr));
225839529caSEd Maste
226839529caSEd Maste /* Update PE optional header. */
227839529caSEd Maste if (pe_update_opt_header(pe, &poh) < 0)
228839529caSEd Maste err(EXIT_FAILURE, "pe_update_opt_header() failed");
229839529caSEd Maste
230839529caSEd Maste /* Write out PE/COFF object. */
231839529caSEd Maste if (pe_update(pe) < 0)
232839529caSEd Maste err(EXIT_FAILURE, "pe_update() failed");
233839529caSEd Maste
234839529caSEd Maste pe_finish(pe);
235839529caSEd Maste elf_end(e);
236839529caSEd Maste }
237