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
libpe_parse_coff_header(PE * pe,char * hdr)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
libpe_write_pe_header(PE * pe,off_t off)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
libpe_write_coff_header(PE * pe,off_t off)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