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 37*d38447b5SEd Maste ELFTC_VCSID("$Id: pe.c 3477 2016-05-25 20:00:42Z kaiwang27 $"); 38839529caSEd Maste 39839529caSEd Maste /* Convert ELF object to Portable Executable (PE). */ 40839529caSEd Maste void 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; 57*d38447b5SEd Maste int elferr; 58839529caSEd Maste 59839529caSEd Maste if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64) 60839529caSEd Maste po = PE_O_PE32P; 61839529caSEd Maste else 62839529caSEd Maste po = PE_O_PE32; 63839529caSEd Maste 64839529caSEd Maste if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) 65839529caSEd Maste errx(EXIT_FAILURE, "elf_begin() failed: %s", 66839529caSEd Maste elf_errmsg(-1)); 67839529caSEd Maste 68839529caSEd Maste if (gelf_getehdr(e, &eh) == NULL) 69839529caSEd Maste errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", 70839529caSEd Maste elf_errmsg(-1)); 71839529caSEd Maste 72839529caSEd Maste if (elf_getshstrndx(ecp->ein, &indx) == 0) 73839529caSEd Maste errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s", 74839529caSEd Maste elf_errmsg(-1)); 75839529caSEd Maste 76839529caSEd Maste if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL) 77839529caSEd Maste err(EXIT_FAILURE, "pe_init() failed"); 78839529caSEd Maste 79839529caSEd Maste /* Setup PE COFF header. */ 80839529caSEd Maste memset(&pch, 0, sizeof(pch)); 81839529caSEd Maste switch (ecp->oem) { 82839529caSEd Maste case EM_386: 83839529caSEd Maste pch.ch_machine = IMAGE_FILE_MACHINE_I386; 84839529caSEd Maste break; 85839529caSEd Maste case EM_X86_64: 86839529caSEd Maste pch.ch_machine = IMAGE_FILE_MACHINE_AMD64; 87839529caSEd Maste break; 88839529caSEd Maste default: 89839529caSEd Maste pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN; 90839529caSEd Maste break; 91839529caSEd Maste } 92839529caSEd Maste pch.ch_timestamp = (uint32_t) time(NULL); 93839529caSEd Maste if (pe_update_coff_header(pe, &pch) < 0) 94839529caSEd Maste err(EXIT_FAILURE, "pe_update_coff_header() failed"); 95839529caSEd Maste 96839529caSEd Maste /* Setup PE optional header. */ 97839529caSEd Maste memset(&poh, 0, sizeof(poh)); 98839529caSEd Maste if (ecp->otf == ETF_EFI) 99839529caSEd Maste poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION; 100839529caSEd Maste poh.oh_entry = (uint32_t) eh.e_entry; 101839529caSEd Maste 102839529caSEd Maste /* 103839529caSEd Maste * Default section alignment and file alignment. (Here the 104839529caSEd Maste * section alignment is set to the default page size of the 105839529caSEd Maste * archs supported. We should use different section alignment 106839529caSEd Maste * for some arch. (e.g. IA64) 107839529caSEd Maste */ 108839529caSEd Maste poh.oh_secalign = 0x1000; 109839529caSEd Maste poh.oh_filealign = 0x200; 110839529caSEd Maste 111839529caSEd Maste /* Copy sections. */ 112839529caSEd Maste scn = NULL; 113839529caSEd Maste while ((scn = elf_nextscn(e, scn)) != NULL) { 114839529caSEd Maste 115839529caSEd Maste /* 116839529caSEd Maste * Read in ELF section. 117839529caSEd Maste */ 118839529caSEd Maste 119839529caSEd Maste if (gelf_getshdr(scn, &sh) == NULL) { 120839529caSEd Maste warnx("gelf_getshdr() failed: %s", elf_errmsg(-1)); 121839529caSEd Maste (void) elf_errno(); 122839529caSEd Maste continue; 123839529caSEd Maste } 124839529caSEd Maste if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == 125839529caSEd Maste NULL) { 126839529caSEd Maste warnx("elf_strptr() failed: %s", elf_errmsg(-1)); 127839529caSEd Maste (void) elf_errno(); 128839529caSEd Maste continue; 129839529caSEd Maste } 130839529caSEd Maste 131839529caSEd Maste /* Skip sections unneeded. */ 132839529caSEd Maste if (strcmp(name, ".shstrtab") == 0 || 133839529caSEd Maste strcmp(name, ".symtab") == 0 || 134839529caSEd Maste strcmp(name, ".strtab") == 0) 135839529caSEd Maste continue; 136839529caSEd Maste 137839529caSEd Maste if ((d = elf_getdata(scn, NULL)) == NULL) { 138839529caSEd Maste warnx("elf_getdata() failed: %s", elf_errmsg(-1)); 139839529caSEd Maste (void) elf_errno(); 140839529caSEd Maste continue; 141839529caSEd Maste } 142839529caSEd Maste 143839529caSEd Maste if (strcmp(name, ".text") == 0) { 144839529caSEd Maste poh.oh_textbase = (uint32_t) sh.sh_addr; 145839529caSEd Maste poh.oh_textsize = (uint32_t) roundup(sh.sh_size, 146839529caSEd Maste poh.oh_filealign); 147839529caSEd Maste } else { 148839529caSEd Maste if (po == PE_O_PE32 && strcmp(name, ".data") == 0) 149839529caSEd Maste poh.oh_database = sh.sh_addr; 150839529caSEd Maste if (sh.sh_type == SHT_NOBITS) 151839529caSEd Maste poh.oh_bsssize += (uint32_t) 152839529caSEd Maste roundup(sh.sh_size, poh.oh_filealign); 153839529caSEd Maste else if (sh.sh_flags & SHF_ALLOC) 154839529caSEd Maste poh.oh_datasize += (uint32_t) 155839529caSEd Maste roundup(sh.sh_size, poh.oh_filealign); 156839529caSEd Maste } 157839529caSEd Maste 158839529caSEd Maste /* 159839529caSEd Maste * Create PE/COFF section. 160839529caSEd Maste */ 161839529caSEd Maste 162839529caSEd Maste if ((ps = pe_newscn(pe)) == NULL) { 163839529caSEd Maste warn("pe_newscn() failed"); 164839529caSEd Maste continue; 165839529caSEd Maste } 166839529caSEd Maste 167839529caSEd Maste /* 168839529caSEd Maste * Setup PE/COFF section header. The section name is not 169839529caSEd Maste * NUL-terminated if its length happens to be 8. Long 170839529caSEd Maste * section name should be truncated for PE image according 171839529caSEd Maste * to the PE/COFF specification. 172839529caSEd Maste */ 173839529caSEd Maste memset(&psh, 0, sizeof(psh)); 174839529caSEd Maste strncpy(psh.sh_name, name, sizeof(psh.sh_name)); 175839529caSEd Maste psh.sh_addr = sh.sh_addr; 176839529caSEd Maste psh.sh_virtsize = sh.sh_size; 177839529caSEd Maste if (sh.sh_type != SHT_NOBITS) 178*d38447b5SEd Maste psh.sh_rawsize = roundup(sh.sh_size, poh.oh_filealign); 179839529caSEd Maste else 180839529caSEd Maste psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; 181839529caSEd Maste 182839529caSEd Maste /* 183839529caSEd Maste * Translate ELF section flags to PE/COFF section flags. 184839529caSEd Maste */ 185839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_READ; 186839529caSEd Maste if (sh.sh_flags & SHF_WRITE) 187839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_WRITE; 188839529caSEd Maste if (sh.sh_flags & SHF_EXECINSTR) 189839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_EXECUTE | 190839529caSEd Maste IMAGE_SCN_CNT_CODE; 191839529caSEd Maste if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0) 192839529caSEd Maste psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA; 193839529caSEd Maste 194839529caSEd Maste /* Mark relocation section "discardable". */ 195839529caSEd Maste if (strcmp(name, ".reloc") == 0) 196839529caSEd Maste psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE; 197839529caSEd Maste 198839529caSEd Maste if (pe_update_section_header(ps, &psh) < 0) { 199839529caSEd Maste warn("pe_update_section_header() failed"); 200839529caSEd Maste continue; 201839529caSEd Maste } 202839529caSEd Maste 203839529caSEd Maste /* Copy section content. */ 204839529caSEd Maste if ((pb = pe_newbuffer(ps)) == NULL) { 205839529caSEd Maste warn("pe_newbuffer() failed"); 206839529caSEd Maste continue; 207839529caSEd Maste } 208839529caSEd Maste pb->pb_align = 1; 209839529caSEd Maste pb->pb_off = 0; 210*d38447b5SEd Maste pb->pb_size = roundup(sh.sh_size, poh.oh_filealign); 211*d38447b5SEd Maste if ((pb->pb_buf = calloc(1, pb->pb_size)) == NULL) { 212*d38447b5SEd Maste warn("calloc failed"); 213*d38447b5SEd Maste continue; 214*d38447b5SEd Maste } 215*d38447b5SEd Maste memcpy(pb->pb_buf, d->d_buf, sh.sh_size); 216839529caSEd Maste } 217839529caSEd Maste elferr = elf_errno(); 218839529caSEd Maste if (elferr != 0) 219839529caSEd Maste warnx("elf_nextscn() failed: %s", elf_errmsg(elferr)); 220839529caSEd Maste 221839529caSEd Maste /* Update PE optional header. */ 222839529caSEd Maste if (pe_update_opt_header(pe, &poh) < 0) 223839529caSEd Maste err(EXIT_FAILURE, "pe_update_opt_header() failed"); 224839529caSEd Maste 225839529caSEd Maste /* Write out PE/COFF object. */ 226839529caSEd Maste if (pe_update(pe) < 0) 227839529caSEd Maste err(EXIT_FAILURE, "pe_update() failed"); 228839529caSEd Maste 229839529caSEd Maste pe_finish(pe); 230839529caSEd Maste elf_end(e); 231839529caSEd Maste } 232