xref: /freebsd/contrib/elftoolchain/libpe/libpe_coff.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1 /*-
2  * Copyright (c) 2015 Kai Wang
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/param.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33 #include <unistd.h>
34 
35 #include "_libpe.h"
36 
37 ELFTC_VCSID("$Id: libpe_coff.c 3326 2016-01-16 17:46:17Z kaiwang27 $");
38 
39 int
40 libpe_parse_coff_header(PE *pe, char *hdr)
41 {
42 	char tmp[128];
43 	PE_CoffHdr *ch;
44 	PE_OptHdr *oh;
45 	PE_DataDir *dd;
46 	unsigned p, r, s;
47 	int i;
48 
49 	if ((ch = malloc(sizeof(PE_CoffHdr))) == NULL) {
50 		errno = ENOMEM;
51 		return (-1);
52 	}
53 
54 	PE_READ16(hdr, ch->ch_machine);
55 	PE_READ16(hdr, ch->ch_nsec);
56 	PE_READ32(hdr, ch->ch_timestamp);
57 	PE_READ32(hdr, ch->ch_symptr);
58 	PE_READ32(hdr, ch->ch_nsym);
59 	PE_READ16(hdr, ch->ch_optsize);
60 	PE_READ16(hdr, ch->ch_char);
61 
62 	pe->pe_ch = ch;
63 
64 	/*
65 	 * The Optional header is omitted for object files.
66 	 */
67 	if (ch->ch_optsize == 0)
68 		return (libpe_parse_section_headers(pe));
69 
70 	if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
71 		errno = ENOMEM;
72 		return (-1);
73 	}
74 	pe->pe_oh = oh;
75 
76 #define READ_OPT(n)							\
77 	do {								\
78 		/*							\
79 		 * Since the Optional Header size is variable, we must	\
80 		 * check if the requested read size will overrun the	\
81 		 * remaining header bytes.				\
82 		 */							\
83 		if (p + (n) > ch->ch_optsize) {				\
84 			/* Consume the "extra" bytes */			\
85 			r = ch->ch_optsize - p;				\
86 			if (read(pe->pe_fd, tmp, r) != (ssize_t) r) {	\
87 				pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;\
88 				return (0);				\
89 			}						\
90 			return (libpe_parse_section_headers(pe));	\
91 		}							\
92 		if (read(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) {	\
93 			pe->pe_flags |= LIBPE_F_BAD_OPT_HEADER;	\
94 			return (0);					\
95 		}							\
96 		p += (n);						\
97 	} while (0)
98 #define	READ_OPT8(v) do { READ_OPT(1); (v) = *tmp; } while(0)
99 #define	READ_OPT16(v) do { READ_OPT(2); (v) = le16dec(tmp); } while(0)
100 #define	READ_OPT32(v) do { READ_OPT(4); (v) = le32dec(tmp); } while(0)
101 #define	READ_OPT64(v) do { READ_OPT(8); (v) = le64dec(tmp); } while(0)
102 
103 	/*
104 	 * Read in the Optional header. Size of some fields are depending
105 	 * on the PE format specified by the oh_magic field. (PE32 or PE32+)
106 	 */
107 
108 	p = 0;
109 	READ_OPT16(oh->oh_magic);
110 	if (oh->oh_magic == PE_FORMAT_32P)
111 		pe->pe_obj = PE_O_PE32P;
112 	READ_OPT8(oh->oh_ldvermajor);
113 	READ_OPT8(oh->oh_ldverminor);
114 	READ_OPT32(oh->oh_textsize);
115 	READ_OPT32(oh->oh_datasize);
116 	READ_OPT32(oh->oh_bsssize);
117 	READ_OPT32(oh->oh_entry);
118 	READ_OPT32(oh->oh_textbase);
119 	if (oh->oh_magic != PE_FORMAT_32P) {
120 		READ_OPT32(oh->oh_database);
121 		READ_OPT32(oh->oh_imgbase);
122 	} else
123 		READ_OPT64(oh->oh_imgbase);
124 	READ_OPT32(oh->oh_secalign);
125 	READ_OPT32(oh->oh_filealign);
126 	READ_OPT16(oh->oh_osvermajor);
127 	READ_OPT16(oh->oh_osverminor);
128 	READ_OPT16(oh->oh_imgvermajor);
129 	READ_OPT16(oh->oh_imgverminor);
130 	READ_OPT16(oh->oh_subvermajor);
131 	READ_OPT16(oh->oh_subverminor);
132 	READ_OPT32(oh->oh_win32ver);
133 	READ_OPT32(oh->oh_imgsize);
134 	READ_OPT32(oh->oh_hdrsize);
135 	READ_OPT32(oh->oh_checksum);
136 	READ_OPT16(oh->oh_subsystem);
137 	READ_OPT16(oh->oh_dllchar);
138 	if (oh->oh_magic != PE_FORMAT_32P) {
139 		READ_OPT32(oh->oh_stacksizer);
140 		READ_OPT32(oh->oh_stacksizec);
141 		READ_OPT32(oh->oh_heapsizer);
142 		READ_OPT32(oh->oh_heapsizec);
143 	} else {
144 		READ_OPT64(oh->oh_stacksizer);
145 		READ_OPT64(oh->oh_stacksizec);
146 		READ_OPT64(oh->oh_heapsizer);
147 		READ_OPT64(oh->oh_heapsizec);
148 	}
149 	READ_OPT32(oh->oh_ldrflags);
150 	READ_OPT32(oh->oh_ndatadir);
151 
152 	/*
153 	 * Read in the Data Directories.
154 	 */
155 
156 	if (oh->oh_ndatadir > 0) {
157 		if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
158 			errno = ENOMEM;
159 			return (-1);
160 		}
161 		pe->pe_dd = dd;
162 
163 		dd->dd_total = oh->oh_ndatadir < PE_DD_MAX ? oh->oh_ndatadir :
164 			PE_DD_MAX;
165 
166 		for (i = 0; (uint32_t) i < dd->dd_total; i++) {
167 			READ_OPT32(dd->dd_e[i].de_addr);
168 			READ_OPT32(dd->dd_e[i].de_size);
169 		}
170 	}
171 
172 	/* Consume the remaining bytes in the Optional header, if any. */
173 	if (ch->ch_optsize > p) {
174 		r = ch->ch_optsize - p;
175 		for (; r > 0; r -= s) {
176 			s = r > sizeof(tmp) ? sizeof(tmp) : r;
177 			if (read(pe->pe_fd, tmp, s) != (ssize_t) s) {
178 				pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
179 				return (0);
180 			}
181 		}
182 	}
183 
184 	return (libpe_parse_section_headers(pe));
185 }
186 
187 off_t
188 libpe_write_pe_header(PE *pe, off_t off)
189 {
190 	char tmp[4];
191 
192 	if (pe->pe_cmd == PE_C_RDWR &&
193 	    (pe->pe_flags & LIBPE_F_BAD_PE_HEADER) == 0) {
194 		assert(pe->pe_dh != NULL);
195 		off = lseek(pe->pe_fd, (off_t) pe->pe_dh->dh_lfanew + 4,
196 		    SEEK_SET);
197 		return (off);
198 	}
199 
200 	/*
201 	 * PE Header should to be aligned on 8-byte boundary according to
202 	 * the PE/COFF specification.
203 	 */
204 	if ((off = libpe_align(pe, off, 8)) < 0)
205 		return (-1);
206 
207 	le32enc(tmp, PE_SIGNATURE);
208 	if (write(pe->pe_fd, tmp, sizeof(tmp)) != (ssize_t) sizeof(tmp)) {
209 		errno = EIO;
210 		return (-1);
211 	}
212 
213 	off += 4;
214 
215 	pe->pe_flags &= ~LIBPE_F_BAD_PE_HEADER;
216 
217 	/* Trigger rewrite for the following headers. */
218 	pe->pe_flags |= LIBPE_F_DIRTY_COFF_HEADER;
219 	pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
220 
221 	return (off);
222 }
223 
224 off_t
225 libpe_write_coff_header(PE *pe, off_t off)
226 {
227 	char tmp[128], *hdr;
228 	PE_CoffHdr *ch;
229 	PE_DataDir *dd;
230 	PE_OptHdr *oh;
231 	PE_Scn *ps;
232 	PE_SecHdr *sh;
233 	unsigned p;
234 	uint32_t reloc_rva, reloc_sz;
235 	int i, reloc;
236 
237 	reloc = 0;
238 	reloc_rva = reloc_sz = 0;
239 
240 	if (pe->pe_cmd == PE_C_RDWR) {
241 		assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
242 
243 		if ((pe->pe_flags & LIBPE_F_DIRTY_COFF_HEADER) == 0 &&
244 		    (pe->pe_flags & LIBPE_F_BAD_COFF_HEADER) == 0) {
245 			if (lseek(pe->pe_fd, (off_t) sizeof(PE_CoffHdr),
246 			    SEEK_CUR) < 0) {
247 				errno = EIO;
248 				return (-1);
249 			}
250 			off += sizeof(PE_CoffHdr);
251 			assert(pe->pe_ch != NULL);
252 			ch = pe->pe_ch;
253 			goto coff_done;
254 		}
255 
256 		/* lseek(2) to the offset of the COFF header. */
257 		if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
258 			errno = EIO;
259 			return (-1);
260 		}
261 	}
262 
263 	if (pe->pe_ch == NULL) {
264 		if ((ch = calloc(1, sizeof(PE_CoffHdr))) == NULL) {
265 			errno = ENOMEM;
266 			return (-1);
267 		}
268 		pe->pe_ch = ch;
269 
270 		/*
271 		 * Default value for ch_machine if not provided by the
272 		 * application.
273 		 */
274 		if (pe->pe_obj == PE_O_PE32P)
275 			ch->ch_machine = IMAGE_FILE_MACHINE_AMD64;
276 		else
277 			ch->ch_machine = IMAGE_FILE_MACHINE_I386;
278 
279 	} else
280 		ch = pe->pe_ch;
281 
282 	if (!ch->ch_timestamp)
283 		ch->ch_timestamp = time(NULL);
284 
285 	if (pe->pe_obj == PE_O_PE32) {
286 		if (!ch->ch_optsize)
287 			ch->ch_optsize = PE_COFF_OPT_SIZE_32;
288 		ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
289 		    IMAGE_FILE_32BIT_MACHINE;
290 	} else if (pe->pe_obj == PE_O_PE32P) {
291 		if (!ch->ch_optsize)
292 			ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
293 		ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
294 		    IMAGE_FILE_LARGE_ADDRESS_AWARE;
295 	} else
296 		ch->ch_optsize = 0;
297 
298 	/*
299 	 * COFF line number is deprecated by the PE/COFF
300 	 * specification. COFF symbol table is deprecated
301 	 * for executables.
302 	 */
303 	ch->ch_char |= IMAGE_FILE_LINE_NUMS_STRIPPED;
304 	if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P)
305 		ch->ch_char |= IMAGE_FILE_LOCAL_SYMS_STRIPPED;
306 
307 	ch->ch_nsec = pe->pe_nscn;
308 
309 	STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
310 		sh = &ps->ps_sh;
311 
312 		if (ps->ps_ndx == 0xFFFFFFFFU) {
313 			ch->ch_symptr = sh->sh_rawptr;
314 			ch->ch_nsym = pe->pe_nsym;
315 		}
316 
317 		if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P) {
318 			if (ps->ps_ndx == (0xFFFF0000 | PE_DD_BASERELOC) ||
319 			    strncmp(sh->sh_name, ".reloc", strlen(".reloc")) ==
320 			    0) {
321 				reloc = 1;
322 				reloc_rva = sh->sh_addr;
323 				reloc_sz = sh->sh_virtsize;
324 			}
325 		}
326 	}
327 
328 	if (!reloc)
329 		ch->ch_char |= IMAGE_FILE_RELOCS_STRIPPED;
330 
331 	if (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) {
332 		if (pe->pe_obj == PE_O_PE32)
333 			ch->ch_optsize = PE_COFF_OPT_SIZE_32;
334 		else if (pe->pe_obj == PE_O_PE32P)
335 			ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
336 		else
337 			ch->ch_optsize = 0;
338 	}
339 
340 	/*
341 	 * Write the COFF header.
342 	 */
343 	hdr = tmp;
344 	PE_WRITE16(hdr, ch->ch_machine);
345 	PE_WRITE16(hdr, ch->ch_nsec);
346 	PE_WRITE32(hdr, ch->ch_timestamp);
347 	PE_WRITE32(hdr, ch->ch_symptr);
348 	PE_WRITE32(hdr, ch->ch_nsym);
349 	PE_WRITE16(hdr, ch->ch_optsize);
350 	PE_WRITE16(hdr, ch->ch_char);
351 	if (write(pe->pe_fd, tmp, sizeof(PE_CoffHdr)) !=
352 	    (ssize_t) sizeof(PE_CoffHdr)) {
353 		errno = EIO;
354 		return (-1);
355 	}
356 
357 coff_done:
358 	off += sizeof(PE_CoffHdr);
359 	pe->pe_flags &= ~LIBPE_F_DIRTY_COFF_HEADER;
360 	pe->pe_flags &= ~LIBPE_F_BAD_COFF_HEADER;
361 	pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
362 
363 	if (ch->ch_optsize == 0)
364 		return (off);
365 
366 	/*
367 	 * Write the Optional header.
368 	 */
369 
370 	if (pe->pe_cmd == PE_C_RDWR) {
371 		if ((pe->pe_flags & LIBPE_F_DIRTY_OPT_HEADER) == 0 &&
372 		    (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) == 0) {
373 			if (lseek(pe->pe_fd, (off_t) ch->ch_optsize,
374 			    SEEK_CUR) < 0) {
375 				errno = EIO;
376 				return (-1);
377 			}
378 			off += ch->ch_optsize;
379 			return (off);
380 		}
381 
382 	}
383 
384 	if (pe->pe_oh == NULL) {
385 		if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
386 			errno = ENOMEM;
387 			return (-1);
388 		}
389 		pe->pe_oh = oh;
390 	} else
391 		oh = pe->pe_oh;
392 
393 	if (pe->pe_obj == PE_O_PE32)
394 		oh->oh_magic = PE_FORMAT_32;
395 	else
396 		oh->oh_magic = PE_FORMAT_32P;
397 
398 	/*
399 	 * LinkerVersion should not be less than 2.5, which will cause
400 	 * Windows to complain the executable is invalid in some case.
401 	 * By default we set LinkerVersion to 2.22 (binutils 2.22)
402 	 */
403 	if (!oh->oh_ldvermajor && !oh->oh_ldverminor) {
404 		oh->oh_ldvermajor = 2;
405 		oh->oh_ldverminor = 22;
406 	}
407 
408 	/*
409 	 * The library always tries to write out all 16 data directories
410 	 * but the actual data dir written will depend on ch_optsize.
411 	 */
412 	oh->oh_ndatadir = PE_DD_MAX;
413 
414 	if (!oh->oh_filealign)
415 		oh->oh_filealign = 0x200;
416 	if (!oh->oh_secalign)
417 		oh->oh_secalign = 0x1000;
418 	oh->oh_hdrsize = roundup(off + ch->ch_optsize + pe->pe_nscn *
419 	    sizeof(PE_SecHdr), oh->oh_filealign);
420 	oh->oh_imgsize = roundup(pe->pe_rvamax, oh->oh_secalign);
421 
422 #define WRITE_OPT(n)							\
423 	do {								\
424 		/*							\
425 		 * Since the Optional Header size is variable, we must	\
426 		 * check if the requested write size will overrun the	\
427 		 * remaining header bytes.				\
428 		 */							\
429 		if (p + (n) > ch->ch_optsize) {				\
430 			/* Pad the "extra" bytes */			\
431 			if (libpe_pad(pe, ch->ch_optsize - p) < 0) {	\
432 				errno = EIO;				\
433 				return (-1);				\
434 			}						\
435 			goto opt_done;					\
436 		}							\
437 		if (write(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) {	\
438 			errno = EIO;					\
439 			return (-1);					\
440 		}							\
441 		p += (n);						\
442 	} while (0)
443 #define	WRITE_OPT8(v) do { *tmp = (v); WRITE_OPT(1); } while(0)
444 #define	WRITE_OPT16(v) do { le16enc(tmp, (v)); WRITE_OPT(2); } while(0)
445 #define	WRITE_OPT32(v) do { le32enc(tmp, (v)); WRITE_OPT(4); } while(0)
446 #define	WRITE_OPT64(v) do { le64enc(tmp, (v)); WRITE_OPT(8); } while(0)
447 
448 	p = 0;
449 	WRITE_OPT16(oh->oh_magic);
450 	if (oh->oh_magic == PE_FORMAT_32P)
451 		pe->pe_obj = PE_O_PE32P;
452 	WRITE_OPT8(oh->oh_ldvermajor);
453 	WRITE_OPT8(oh->oh_ldverminor);
454 	WRITE_OPT32(oh->oh_textsize);
455 	WRITE_OPT32(oh->oh_datasize);
456 	WRITE_OPT32(oh->oh_bsssize);
457 	WRITE_OPT32(oh->oh_entry);
458 	WRITE_OPT32(oh->oh_textbase);
459 	if (oh->oh_magic != PE_FORMAT_32P) {
460 		WRITE_OPT32(oh->oh_database);
461 		WRITE_OPT32(oh->oh_imgbase);
462 	} else
463 		WRITE_OPT64(oh->oh_imgbase);
464 	WRITE_OPT32(oh->oh_secalign);
465 	WRITE_OPT32(oh->oh_filealign);
466 	WRITE_OPT16(oh->oh_osvermajor);
467 	WRITE_OPT16(oh->oh_osverminor);
468 	WRITE_OPT16(oh->oh_imgvermajor);
469 	WRITE_OPT16(oh->oh_imgverminor);
470 	WRITE_OPT16(oh->oh_subvermajor);
471 	WRITE_OPT16(oh->oh_subverminor);
472 	WRITE_OPT32(oh->oh_win32ver);
473 	WRITE_OPT32(oh->oh_imgsize);
474 	WRITE_OPT32(oh->oh_hdrsize);
475 	WRITE_OPT32(oh->oh_checksum);
476 	WRITE_OPT16(oh->oh_subsystem);
477 	WRITE_OPT16(oh->oh_dllchar);
478 	if (oh->oh_magic != PE_FORMAT_32P) {
479 		WRITE_OPT32(oh->oh_stacksizer);
480 		WRITE_OPT32(oh->oh_stacksizec);
481 		WRITE_OPT32(oh->oh_heapsizer);
482 		WRITE_OPT32(oh->oh_heapsizec);
483 	} else {
484 		WRITE_OPT64(oh->oh_stacksizer);
485 		WRITE_OPT64(oh->oh_stacksizec);
486 		WRITE_OPT64(oh->oh_heapsizer);
487 		WRITE_OPT64(oh->oh_heapsizec);
488 	}
489 	WRITE_OPT32(oh->oh_ldrflags);
490 	WRITE_OPT32(oh->oh_ndatadir);
491 
492 	/*
493 	 * Write the Data Directories.
494 	 */
495 
496 	if (oh->oh_ndatadir > 0) {
497 		if (pe->pe_dd == NULL) {
498 			if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
499 				errno = ENOMEM;
500 				return (-1);
501 			}
502 			pe->pe_dd = dd;
503 			dd->dd_total = PE_DD_MAX;
504 		} else
505 			dd = pe->pe_dd;
506 
507 		assert(oh->oh_ndatadir <= PE_DD_MAX);
508 
509 		if (reloc) {
510 			dd->dd_e[PE_DD_BASERELOC].de_addr = reloc_rva;
511 			dd->dd_e[PE_DD_BASERELOC].de_size = reloc_sz;
512 		}
513 
514 		for (i = 0; (uint32_t) i < dd->dd_total; i++) {
515 			WRITE_OPT32(dd->dd_e[i].de_addr);
516 			WRITE_OPT32(dd->dd_e[i].de_size);
517 		}
518 	}
519 
520 	/* Pad the remaining bytes in the Optional header, if any. */
521 	if (ch->ch_optsize > p) {
522 		if (libpe_pad(pe, ch->ch_optsize - p) < 0) {
523 			errno = EIO;
524 			return (-1);
525 		}
526 	}
527 
528 opt_done:
529 	off += ch->ch_optsize;
530 	pe->pe_flags &= ~LIBPE_F_DIRTY_OPT_HEADER;
531 	pe->pe_flags &= ~LIBPE_F_BAD_OPT_HEADER;
532 	pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
533 
534 	return (off);
535 }
536