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
37ELFTC_VCSID("$Id: libpe_coff.c 3326 2016-01-16 17:46:17Z kaiwang27 $");
38
39int
40libpe_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
187off_t
188libpe_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
224off_t
225libpe_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
357coff_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
528opt_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