1 /* pefile.cpp --
2
3 This file is part of the UPX executable compressor.
4
5 Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
6 Copyright (C) 1996-2020 Laszlo Molnar
7 All Rights Reserved.
8
9 UPX and the UCL library are free software; you can redistribute them
10 and/or modify them under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of
12 the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; see the file COPYING.
21 If not, write to the Free Software Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Markus F.X.J. Oberhumer Laszlo Molnar
25 <markus@oberhumer.com> <ezerotven+github@gmail.com>
26 */
27
28
29 #include "conf.h"
30 #include "file.h"
31 #include "filter.h"
32 #include "packer.h"
33 #include "pefile.h"
34 #include "linker.h"
35
36 #define FILLVAL 0
37
38 /*************************************************************************
39 //
40 **************************************************************************/
41
42 #include "bptr.h"
43 #define IPTR(type, var) BoundedPtr<type> var(ibuf, ibuf.getSize())
44 #define OPTR(type, var) BoundedPtr<type> var(obuf, obuf.getSize())
45 #define IPTR_I_D(type, var, disp) \
46 BoundedPtr<type> var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp))
47 #define IPTR_I(type, var, v) BoundedPtr<type> var(ibuf, ibuf.getSize(), v)
48 #define OPTR_I(type, var, v) BoundedPtr<type> var(obuf, obuf.getSize(), v)
49 #define IPTR_C(type, var, v) const BoundedPtr<type> var(ibuf, ibuf.getSize(), v)
50 #define OPTR_C(type, var, v) const BoundedPtr<type> var(obuf, obuf.getSize(), v)
51
xcheck(const void * p)52 static void xcheck(const void *p)
53 {
54 if (!p)
55 throwCantUnpack("unexpected NULL pointer; take care!");
56 }
xcheck(const void * p,size_t plen,const void * b,size_t blen)57 static void xcheck(const void *p, size_t plen, const void *b, size_t blen)
58 {
59 const char *pp = (const char *) p;
60 const char *bb = (const char *) b;
61 if (pp < bb || pp > bb + blen || pp + plen > bb + blen)
62 throwCantUnpack("pointer out of range; take care!");
63 }
64 #if 0
65 static void xcheck(size_t poff, size_t plen, const void *b, size_t blen)
66 {
67 ACC_UNUSED(b);
68 if (poff > blen || poff + plen > blen)
69 throwCantUnpack("pointer out of range; take care!");
70 }
71 #endif
72 #define ICHECK(x, size) xcheck(x, size, ibuf, ibuf.getSize())
73 #define OCHECK(x, size) xcheck(x, size, obuf, obuf.getSize())
74
75 #define imemset(a,b,c) ICHECK(a,c), memset(a,b,c)
76 #define omemset(a,b,c) OCHECK(a,c), memset(a,b,c)
77 #define imemcpy(a,b,c) ICHECK(a,c), memcpy(a,b,c)
78 #define omemcpy(a,b,c) OCHECK(a,c), memcpy(a,b,c)
79
80
81 /*************************************************************************
82 //
83 **************************************************************************/
84
PeFile(InputFile * f)85 PeFile::PeFile(InputFile *f) : super(f)
86 {
87 bele = &N_BELE_RTP::le_policy;
88 COMPILE_TIME_ASSERT(sizeof(ddirs_t) == 8)
89 COMPILE_TIME_ASSERT(sizeof(pe_section_t) == 40)
90 COMPILE_TIME_ASSERT_ALIGNED1(ddirs_t)
91 COMPILE_TIME_ASSERT_ALIGNED1(pe_section_t)
92 COMPILE_TIME_ASSERT(RT_LAST == TABLESIZE(opt->win32_pe.compress_rt))
93
94 isection = NULL;
95 oimport = NULL;
96 oimpdlls = NULL;
97 orelocs = NULL;
98 oexport = NULL;
99 otls = NULL;
100 oresources = NULL;
101 oxrelocs = NULL;
102 icondir_offset = 0;
103 icondir_count = 0;
104 importbyordinal = false;
105 kernel32ordinal = false;
106 tlsindex = 0;
107 big_relocs = 0;
108 sorelocs = 0;
109 soxrelocs = 0;
110 sotls = 0;
111 isdll = false;
112 ilinker = NULL;
113 use_tls_callbacks = false;
114 oloadconf = NULL;
115 soloadconf = 0;
116
117 use_dep_hack = true;
118 use_clear_dirty_stack = true;
119 isrtm = false;
120 }
121
122
testUnpackVersion(int version) const123 bool PeFile::testUnpackVersion(int version) const
124 {
125 if (version != ph_version && ph_version != -1)
126 throwCantUnpack("program has been modified; run a virus checker!");
127 if (!canUnpackVersion(version))
128 throwCantUnpack("this program is packed with an obsolete version and cannot be unpacked");
129 return true;
130 }
131
132
133 /*************************************************************************
134 // util
135 **************************************************************************/
136
readFileHeader()137 int PeFile::readFileHeader()
138 {
139 __packed_struct(exe_header_t)
140 LE16 mz;
141 LE16 m512;
142 LE16 p512;
143 char _[18];
144 LE16 relocoffs;
145 char __[34];
146 LE32 nexepos;
147 __packed_struct_end()
148
149 COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 64)
150 COMPILE_TIME_ASSERT_ALIGNED1(exe_header_t)
151 COMPILE_TIME_ASSERT(sizeof(((exe_header_t*)0)->_) == 18)
152 COMPILE_TIME_ASSERT(sizeof(((exe_header_t*)0)->__) == 34)
153
154 exe_header_t h;
155 int ic;
156 pe_offset = 0;
157
158 for (ic = 0; ic < 20; ic++)
159 {
160 fi->seek(pe_offset,SEEK_SET);
161 fi->readx(&h,sizeof(h));
162
163 if (h.mz == 'M' + 'Z'*256) // dos exe
164 {
165 unsigned const delta = (h.relocoffs >= 0x40)
166 ? h.nexepos // new format exe
167 : (h.p512*512+h.m512 - h.m512 ? 512 : h.nexepos);
168
169 if ((pe_offset + delta) < delta // wrap-around
170 || (pe_offset + delta) > (unsigned)file_size) {
171 char buf[64]; snprintf(buf, sizeof(buf),
172 "bad PE delta %#x at offset %#x", delta, pe_offset);
173 throwCantPack(buf);
174 }
175 pe_offset += delta;
176 }
177 else if (get_le32(&h) == 'P' + 'E'*256)
178 break;
179 else
180 return 0;
181 }
182 if (ic == 20)
183 return 0;
184 fi->seek(pe_offset,SEEK_SET);
185 readPeHeader();
186 fi->seek(0x200,SEEK_SET);
187 fi->readx(&h,6);
188 return getFormat();
189 }
190
191
192 /*************************************************************************
193 // interval handling
194 **************************************************************************/
195
Interval(void * b)196 PeFile::Interval::Interval(void *b) : capacity(0),base(b),ivarr(NULL),ivnum(0)
197 {}
198
~Interval()199 PeFile::Interval::~Interval()
200 {
201 free(ivarr);
202 }
203
add(const void * start,unsigned len)204 void PeFile::Interval::add(const void *start,unsigned len)
205 {
206 add(ptr_diff(start,base),len);
207 }
208
add(const void * start,const void * end)209 void PeFile::Interval::add(const void *start,const void *end)
210 {
211 add(ptr_diff(start,base),ptr_diff(end,start));
212 }
213
compare(const void * p1,const void * p2)214 int __acc_cdecl_qsort PeFile::Interval::compare(const void *p1,const void *p2)
215 {
216 const interval *i1 = (const interval*) p1;
217 const interval *i2 = (const interval*) p2;
218 if (i1->start < i2->start) return -1;
219 if (i1->start > i2->start) return 1;
220 if (i1->len < i2->len) return 1;
221 if (i1->len > i2->len) return -1;
222 return 0;
223 }
224
add(unsigned start,unsigned len)225 void PeFile::Interval::add(unsigned start,unsigned len)
226 {
227 if (ivnum == capacity)
228 ivarr = (interval*) realloc(ivarr,(capacity += 15) * sizeof (interval));
229 ivarr[ivnum].start = start;
230 ivarr[ivnum++].len = len;
231 }
232
add(const Interval * iv)233 void PeFile::Interval::add(const Interval *iv)
234 {
235 for (unsigned ic = 0; ic < iv->ivnum; ic++)
236 add(iv->ivarr[ic].start,iv->ivarr[ic].len);
237 }
238
flatten()239 void PeFile::Interval::flatten()
240 {
241 if (!ivnum)
242 return;
243 qsort(ivarr,ivnum,sizeof (interval),Interval::compare);
244 for (unsigned ic = 0; ic < ivnum - 1; ic++)
245 {
246 unsigned jc;
247 for (jc = ic + 1; jc < ivnum && ivarr[ic].start + ivarr[ic].len >= ivarr[jc].start; jc++)
248 if (ivarr[ic].start + ivarr[ic].len < ivarr[jc].start + ivarr[jc].len)
249 ivarr[ic].len = ivarr[jc].start + ivarr[jc].len - ivarr[ic].start;
250 if (jc > ic + 1)
251 {
252 memmove(ivarr + ic + 1, ivarr + jc,sizeof(interval) * (ivnum - jc));
253 ivnum -= jc - ic - 1;
254 }
255 }
256 }
257
clear()258 void PeFile::Interval::clear()
259 {
260 for (unsigned ic = 0; ic < ivnum; ic++)
261 memset((char*) base + ivarr[ic].start,0,ivarr[ic].len);
262 }
263
dump() const264 void PeFile::Interval::dump() const
265 {
266 printf("%d intervals:\n",ivnum);
267 for (unsigned ic = 0; ic < ivnum; ic++)
268 printf("%x %x\n",ivarr[ic].start,ivarr[ic].len);
269 }
270
271
272 /*************************************************************************
273 // relocation handling
274 **************************************************************************/
275
276 __packed_struct(PeFile::Reloc::reloc)
277 LE32 pagestart;
278 LE32 size;
__packed_struct_end()279 __packed_struct_end()
280
281 void PeFile::Reloc::newRelocPos(void *p)
282 {
283 rel = (reloc*) p;
284 rel1 = (LE16*) ((char*) p + sizeof (reloc));
285 }
286
Reloc(upx_byte * s,unsigned si)287 PeFile::Reloc::Reloc(upx_byte *s,unsigned si) :
288 start(s), size(si), rel(NULL), rel1(NULL)
289 {
290 COMPILE_TIME_ASSERT(sizeof(reloc) == 8)
291 COMPILE_TIME_ASSERT_ALIGNED1(reloc)
292 memset(counts,0,sizeof(counts));
293 unsigned pos,type;
294 while (next(pos,type))
295 counts[type]++;
296 }
297
Reloc(unsigned rnum)298 PeFile::Reloc::Reloc(unsigned rnum) :
299 start(NULL), size(0), rel(NULL), rel1(NULL)
300 {
301 start = new upx_byte[mem_size(4, rnum, 8192)];
302 counts[0] = 0;
303 }
304
next(unsigned & pos,unsigned & type)305 bool PeFile::Reloc::next(unsigned &pos,unsigned &type)
306 {
307 if (!rel)
308 newRelocPos(start);
309 if (ptr_diff(rel, start) >= (int) size || rel->pagestart == 0)
310 return rel = 0,false; // rewind
311
312 pos = rel->pagestart + (*rel1 & 0xfff);
313 type = *rel1++ >> 12;
314 //printf("%x %d\n",pos,type);
315 if (ptr_diff(rel1,rel) >= (int) rel->size)
316 newRelocPos(rel1);
317 return type == 0 ? next(pos,type) : true;
318 }
319
add(unsigned pos,unsigned type)320 void PeFile::Reloc::add(unsigned pos,unsigned type)
321 {
322 set_le32(start + 1024 + 4 * counts[0]++,(pos << 4) + type);
323 }
324
finish(upx_byte * & p,unsigned & siz)325 void PeFile::Reloc::finish(upx_byte *&p,unsigned &siz)
326 {
327 unsigned prev = 0xffffffff;
328 set_le32(start + 1024 + 4 * counts[0]++,0xf0000000);
329 qsort(start + 1024,counts[0],4,le32_compare);
330
331 rel = (reloc*) start;
332 rel1 = (LE16*) start;
333 for (unsigned ic = 0; ic < counts[0]; ic++)
334 {
335 unsigned pos = get_le32(start + 1024 + 4 * ic);
336 if ((pos ^ prev) >= 0x10000)
337 {
338 prev = pos;
339 *rel1 = 0;
340 rel->size = ALIGN_UP(ptr_diff(rel1,rel), 4);
341 newRelocPos((char *)rel + rel->size);
342 rel->pagestart = (pos >> 4) &~ 0xfff;
343 }
344 *rel1++ = (pos << 12) + ((pos >> 4) & 0xfff);
345 }
346 p = start;
347 siz = ptr_diff(rel1,start) &~ 3;
348 siz -= 8;
349 // siz can be 0 in 64-bit mode // assert(siz > 0);
350 start = 0; // safety
351 }
352
processRelocs(Reloc * rel)353 void PeFile::processRelocs(Reloc *rel) // pass2
354 {
355 rel->finish(oxrelocs,soxrelocs);
356 if (opt->win32_pe.strip_relocs && !isdll /*FIXME ASLR*/)
357 soxrelocs = 0;
358 }
359
processRelocs()360 void PeFile32::processRelocs() // pass1
361 {
362 big_relocs = 0;
363
364 unsigned const take1 = IDSIZE(PEDIR_RELOC);
365 unsigned const skip1 = IDADDR(PEDIR_RELOC);
366 Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1);
367 const unsigned *counts = rel.getcounts();
368 const unsigned rnum = counts[1] + counts[2] + counts[3];
369
370 if ((opt->win32_pe.strip_relocs && !isdll) || rnum == 0)
371 {
372 if (IDSIZE(PEDIR_RELOC))
373 ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
374 orelocs = new upx_byte [1];
375 sorelocs = 0;
376 return;
377 }
378
379 unsigned ic;
380 for (ic = 15; ic > 3; ic--)
381 if (counts[ic])
382 infoWarning("skipping unsupported relocation type %d (%d)",ic,counts[ic]);
383
384 LE32 *fix[4];
385 for (; ic; ic--)
386 fix[ic] = New(LE32, counts[ic]);
387
388 unsigned xcounts[4];
389 memset(xcounts, 0, sizeof(xcounts));
390
391 // prepare sorting
392 unsigned pos,type;
393 while (rel.next(pos,type))
394 {
395 if (pos >= ih.imagesize)
396 continue; // skip out-of-bounds record
397 if (type < 4)
398 fix[type][xcounts[type]++] = pos - rvamin;
399 }
400
401 // remove duplicated records
402 for (ic = 1; ic <= 3; ic++)
403 {
404 qsort(fix[ic], xcounts[ic], 4, le32_compare);
405 unsigned prev = ~0u;
406 unsigned jc = 0;
407 for (unsigned kc = 0; kc < xcounts[ic]; kc++)
408 if (fix[ic][kc] != prev)
409 prev = fix[ic][jc++] = fix[ic][kc];
410
411 //printf("xcounts[%u] %u->%u\n", ic, xcounts[ic], jc);
412 xcounts[ic] = jc;
413 }
414
415 // preprocess "type 3" relocation records
416 for (ic = 0; ic < xcounts[3]; ic++)
417 {
418 pos = fix[3][ic] + rvamin;
419 unsigned w = get_le32(ibuf.subref("bad reloc type 3 %#x", pos, sizeof(LE32)));
420 set_le32(ibuf + pos, w - ih.imagebase - rvamin);
421 }
422
423 ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
424 orelocs = new upx_byte [mem_size(4, rnum, 1024)]; // 1024 - safety
425 sorelocs = ptr_diff(optimizeReloc32((upx_byte*) fix[3], xcounts[3],
426 orelocs, ibuf + rvamin, 1, &big_relocs),
427 orelocs);
428 delete [] fix[3];
429
430 // Malware that hides behind UPX often has PE header info that is
431 // deliberately corrupt. Sometimes it is even tuned to cause us trouble!
432 // Use an extra check to avoid AccessViolation (SIGSEGV) when appending
433 // the relocs into one array.
434 if ((rnum * 4 + 1024) < (sorelocs + 4*(2 + xcounts[2] + xcounts[1])))
435 throwCantUnpack("Invalid relocs");
436
437 // append relocs type "LOW" then "HIGH"
438 for (ic = 2; ic ; ic--)
439 {
440 memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]);
441 sorelocs += 4 * xcounts[ic];
442 delete [] fix[ic];
443
444 set_le32(orelocs + sorelocs,0);
445 if (xcounts[ic])
446 {
447 sorelocs += 4;
448 big_relocs |= 2 * ic;
449 }
450 }
451 info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs);
452 }
453
454 // FIXME - this is too similar to PeFile32::processRelocs
processRelocs()455 void PeFile64::processRelocs() // pass1
456 {
457 big_relocs = 0;
458
459 unsigned const take = IDSIZE(PEDIR_RELOC);
460 unsigned const skip = IDADDR(PEDIR_RELOC);
461 Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
462 const unsigned *counts = rel.getcounts();
463 unsigned rnum = 0;
464
465 unsigned ic;
466 for (ic = 1; ic < 16; ic++)
467 rnum += counts[ic];
468
469 if ((opt->win32_pe.strip_relocs && !isdll) || rnum == 0)
470 {
471 if (IDSIZE(PEDIR_RELOC))
472 ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
473 orelocs = new upx_byte [1];
474 sorelocs = 0;
475 return;
476 }
477
478 for (ic = 15; ic; ic--)
479 if (ic != 10 && counts[ic])
480 infoWarning("skipping unsupported relocation type %d (%d)",ic,counts[ic]);
481
482 LE32 *fix[16];
483 for (ic = 15; ic; ic--)
484 fix[ic] = New(LE32, counts[ic]);
485
486 unsigned xcounts[16];
487 memset(xcounts, 0, sizeof(xcounts));
488
489 // prepare sorting
490 unsigned pos,type;
491 while (rel.next(pos,type))
492 {
493 // FIXME add check for relocations which try to modify the
494 // PE header or other relocation records
495
496 if (pos >= ih.imagesize)
497 continue; // skip out-of-bounds record
498 if (type < 16)
499 fix[type][xcounts[type]++] = pos - rvamin;
500 }
501
502 // remove duplicated records
503 for (ic = 1; ic <= 15; ic++)
504 {
505 qsort(fix[ic], xcounts[ic], 4, le32_compare);
506 unsigned prev = ~0u;
507 unsigned jc = 0;
508 for (unsigned kc = 0; kc < xcounts[ic]; kc++)
509 if (fix[ic][kc] != prev)
510 prev = fix[ic][jc++] = fix[ic][kc];
511
512 //printf("xcounts[%u] %u->%u\n", ic, xcounts[ic], jc);
513 xcounts[ic] = jc;
514 }
515
516 // preprocess "type 10" relocation records
517 for (ic = 0; ic < xcounts[10]; ic++)
518 {
519 pos = fix[10][ic] + rvamin;
520 upx_uint64_t w = get_le64(ibuf.subref("bad reloc 10 %#x", pos, sizeof(LE64)));
521 set_le64(ibuf + pos, w - ih.imagebase - rvamin);
522 }
523
524 ibuf.fill(IDADDR(PEDIR_RELOC), IDSIZE(PEDIR_RELOC), FILLVAL);
525 orelocs = new upx_byte [mem_size(4, rnum, 1024)]; // 1024 - safety
526 sorelocs = ptr_diff(optimizeReloc64((upx_byte*) fix[10], xcounts[10],
527 orelocs, ibuf + rvamin, 1, &big_relocs),
528 orelocs);
529
530 for (ic = 15; ic; ic--)
531 delete [] fix[ic];
532
533 #if 0
534 // Malware that hides behind UPX often has PE header info that is
535 // deliberately corrupt. Sometimes it is even tuned to cause us trouble!
536 // Use an extra check to avoid AccessViolation (SIGSEGV) when appending
537 // the relocs into one array.
538 if ((rnum * 4 + 1024) < (sorelocs + 4*(2 + xcounts[2] + xcounts[1])))
539 throwCantUnpack("Invalid relocs");
540
541 // append relocs type "LOW" then "HIGH"
542 for (ic = 2; ic ; ic--)
543 {
544 memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]);
545 sorelocs += 4 * xcounts[ic];
546 delete [] fix[ic];
547
548 set_le32(orelocs + sorelocs,0);
549 if (xcounts[ic])
550 {
551 sorelocs += 4;
552 big_relocs |= 2 * ic;
553 }
554 }
555 #endif
556 info("Relocations: original size: %u bytes, preprocessed size: %u bytes",(unsigned) IDSIZE(PEDIR_RELOC),sorelocs);
557 }
558
559 /*************************************************************************
560 // import handling
561 **************************************************************************/
562
IDSIZE(unsigned x)563 LE32& PeFile::IDSIZE(unsigned x) { return iddirs[x].size; }
IDADDR(unsigned x)564 LE32& PeFile::IDADDR(unsigned x) { return iddirs[x].vaddr; }
ODSIZE(unsigned x)565 LE32& PeFile::ODSIZE(unsigned x) { return oddirs[x].size; }
ODADDR(unsigned x)566 LE32& PeFile::ODADDR(unsigned x) { return oddirs[x].vaddr; }
567
568 /*
569 ImportLinker: 32 and 64 bit import table building.
570 Import entries (dll name + proc name/ordinal pairs) can be
571 added in arbitrary order.
572
573 Internally it works by creating sections with special names,
574 and adding relocation entries between those sections. The special
575 names ensure that when the import table is built in the memory
576 from those sections, a correct table can be generated simply by
577 sorting the sections by name, and adding all of them to the output
578 in the sorted order.
579 */
580
581 class PeFile::ImportLinker : public ElfLinkerAMD64
582 {
583 struct tstr : private ::noncopyable
584 {
585 char *s;
tstrPeFile::ImportLinker::tstr586 explicit tstr(char *str) : s(str) {}
~tstrPeFile::ImportLinker::tstr587 ~tstr() { delete [] s; }
operator char*PeFile::ImportLinker::tstr588 operator char *() const { return s; }
589 };
590
591 // encoding of dll and proc names are required, so that our special
592 // control characters in the name of sections can work as intended
encode_name(const char * name,char * buf)593 static char *encode_name(const char *name, char *buf)
594 {
595 char *b = buf;
596 while (*name)
597 {
598 *b++ = 'a' + ((*name >> 4) & 0xf);
599 *b++ = 'a' + (*name & 0xf);
600 name++;
601 }
602 *b = 0;
603 return buf;
604 }
605
name_for_dll(const char * dll,char first_char)606 static char *name_for_dll(const char *dll, char first_char)
607 {
608 assert(dll);
609 unsigned l = strlen(dll);
610 assert(l > 0);
611
612 char *name = New(char, 3 * l + 2);
613 assert(name);
614 name[0] = first_char;
615 char *n = name + 1 + 2 * l;
616 do {
617 *n++ = tolower(*dll);
618 } while(*dll++);
619 return encode_name(name + 1 + 2 * l, name + 1) - 1;
620 }
621
name_for_proc(const char * dll,const char * proc,char first_char,char separator)622 static char *name_for_proc(const char *dll, const char *proc,
623 char first_char, char separator)
624 {
625 unsigned len = 1 + 2 * strlen(dll) + 1 + 2 * strlen(proc) + 1 + 1;
626 tstr dlln(name_for_dll(dll, first_char));
627 char *procn = New(char, len);
628 upx_snprintf(procn, len, "%s%c", (const char*) dlln, separator);
629 encode_name(proc, procn + strlen(procn));
630 return procn;
631 }
632
633 static const char zeros[sizeof(import_desc)];
634
635 enum {
636 // the order of identifiers is very important below!!
637 descriptor_id = 'D',
638 thunk_id,
639 dll_name_id,
640 proc_name_id,
641 ordinal_id,
642
643 thunk_separator_first,
644 thunk_separator,
645 thunk_separator_last,
646 procname_separator,
647 };
648
649 unsigned thunk_size; // 4 or 8 bytes
650
add(const char * dll,const char * proc,unsigned ordinal)651 void add(const char *dll, const char *proc, unsigned ordinal)
652 {
653 tstr sdll(name_for_dll(dll, dll_name_id));
654 tstr desc_name(name_for_dll(dll, descriptor_id));
655
656 char tsep = thunk_separator;
657 if (findSection(sdll, false) == NULL)
658 {
659 tsep = thunk_separator_first;
660 addSection(sdll, dll, strlen(dll) + 1, 0); // name of the dll
661 addSymbol(sdll, sdll, 0);
662
663 addSection(desc_name, zeros, sizeof(zeros), 0); // descriptor
664 addRelocation(desc_name, offsetof(import_desc, dllname),
665 "R_X86_64_32", sdll, 0);
666 }
667 tstr thunk(name_for_proc(dll, proc, thunk_id, tsep));
668 if (findSection(thunk, false) != NULL)
669 return; // we already have this dll/proc
670 addSection(thunk, zeros, thunk_size, 0);
671 addSymbol(thunk, thunk, 0);
672 if (tsep == thunk_separator_first)
673 {
674 addRelocation(desc_name, offsetof(import_desc, iat),
675 "R_X86_64_32", thunk, 0);
676
677 tstr last_thunk(name_for_proc(dll, "X", thunk_id, thunk_separator_last));
678 addSection(last_thunk, zeros, thunk_size, 0);
679 }
680
681 const char *reltype = thunk_size == 4 ? "R_X86_64_32" : "R_X86_64_64";
682 if (ordinal != 0u)
683 {
684 addRelocation(thunk, 0, reltype, "*UND*",
685 ordinal | (1ull << (thunk_size * 8 - 1)));
686 }
687 else
688 {
689 tstr proc_name(name_for_proc(dll, proc, proc_name_id, procname_separator));
690 addSection(proc_name, zeros, 2, 1); // 2 bytes of word aligned "hint"
691 addSymbol(proc_name, proc_name, 0);
692 addRelocation(thunk, 0, reltype, proc_name, 0);
693
694 strcat(proc_name, "X");
695 addSection(proc_name, proc, strlen(proc), 0); // the name of the symbol
696 }
697 }
698
compare(const void * p1,const void * p2)699 static int __acc_cdecl_qsort compare(const void *p1, const void *p2)
700 {
701 const Section *s1 = * (const Section * const *) p1;
702 const Section *s2 = * (const Section * const *) p2;
703 return strcmp(s1->name, s2->name);
704 }
705
alignCode(unsigned len)706 virtual void alignCode(unsigned len) { alignWithByte(len, 0); }
707
getThunk(const char * dll,const char * proc,char tsep) const708 const Section *getThunk(const char *dll, const char *proc, char tsep) const
709 {
710 assert(dll);
711 assert(proc);
712 tstr thunk(name_for_proc(dll, proc, thunk_id, tsep));
713 return findSection(thunk, false);
714 }
715
716 public:
ImportLinker(unsigned thunk_size_)717 explicit ImportLinker(unsigned thunk_size_) : thunk_size(thunk_size_)
718 {
719 assert(thunk_size == 4 || thunk_size == 8);
720 addSection("*UND*", NULL, 0, 0);
721 addSymbol("*UND*", "*UND*", 0);
722 addSection("*ZSTART", NULL, 0, 0);
723 addSymbol("*ZSTART", "*ZSTART", 0);
724 Section *s = addSection("Dzero", zeros, sizeof(import_desc), 0);
725 assert(s->name[0] == descriptor_id);
726
727 // one trailing 00 byte after the last proc name
728 addSection("Zzero", zeros, 1, 0);
729 }
730
731 template <typename C>
add(const C * dll,unsigned ordinal)732 void add(const C *dll, unsigned ordinal)
733 {
734 ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char"
735 assert(ordinal > 0 && ordinal < 0x10000);
736 char ord[1+5+1];
737 upx_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal);
738 add((const char*) dll, ord, ordinal);
739 }
740
741 template <typename C1, typename C2>
add(const C1 * dll,const C2 * proc)742 void add(const C1 *dll, const C2 *proc)
743 {
744 ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "unsigned char"
745 ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "unsigned char"
746 assert(proc);
747 add((const char*) dll, (const char*) proc, 0);
748 }
749
build()750 unsigned build()
751 {
752 assert(output == NULL);
753 int osize = 4 + 2 * nsections; // upper limit for alignments
754 for (unsigned ic = 0; ic < nsections; ic++)
755 osize += sections[ic]->size;
756 output = New(upx_byte, osize);
757 outputlen = 0;
758
759 // sort the sections by name before adding them all
760 qsort(sections, nsections, sizeof (Section*), ImportLinker::compare);
761
762 for (unsigned ic = 0; ic < nsections; ic++)
763 addLoader(sections[ic]->name);
764 addLoader("+40D");
765 assert(outputlen <= osize);
766
767 //OutputFile::dump("il0.imp", output, outputlen);
768 return outputlen;
769 }
770
relocate_import(unsigned myimport)771 void relocate_import(unsigned myimport)
772 {
773 assert(nsections > 0);
774 assert(output);
775 defineSymbol("*ZSTART", /*0xffffffffff1000ull + 0 * */ myimport);
776 ElfLinkerAMD64::relocate();
777 //OutputFile::dump("il1.imp", output, outputlen);
778 }
779
780 template <typename C1, typename C2>
getAddress(const C1 * dll,const C2 * proc) const781 upx_uint64_t getAddress(const C1 *dll, const C2 *proc) const
782 {
783 ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "unsigned char"
784 ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "unsigned char"
785 const Section *s = getThunk((const char*) dll, (const char*) proc,
786 thunk_separator_first);
787 if (s == NULL && (s = getThunk((const char*) dll,(const char*) proc,
788 thunk_separator)) == NULL)
789 throwInternalError("entry not found");
790 return s->offset;
791 }
792
793 template <typename C>
getAddress(const C * dll,unsigned ordinal) const794 upx_uint64_t getAddress(const C *dll, unsigned ordinal) const
795 {
796 ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char"
797 assert(ordinal > 0 && ordinal < 0x10000);
798 char ord[1+5+1];
799 upx_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal);
800
801 const Section *s = getThunk((const char*) dll, ord, thunk_separator_first);
802 if (s == NULL
803 && (s = getThunk((const char*) dll, ord, thunk_separator)) == NULL)
804 throwInternalError("entry not found");
805 return s->offset;
806 }
807
808 template <typename C>
getAddress(const C * dll) const809 upx_uint64_t getAddress(const C *dll) const
810 {
811 ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char"
812 tstr sdll(name_for_dll((const char*) dll, dll_name_id));
813 return findSection(sdll, true)->offset;
814 }
815
816 template <typename C>
hasDll(const C * dll) const817 upx_uint64_t hasDll(const C *dll) const
818 {
819 ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "unsigned char"
820 tstr sdll(name_for_dll((const char*) dll, dll_name_id));
821 return findSection(sdll, false) != NULL;
822 }
823 };
824 const char PeFile::ImportLinker::zeros[sizeof(import_desc)] = { 0 };
825
addKernelImport(const char * name)826 void PeFile::addKernelImport(const char *name)
827 {
828 ilinker->add(kernelDll(), name);
829 }
830
addStubImports()831 void PeFile::addStubImports()
832 {
833 addKernelImport("LoadLibraryA");
834 addKernelImport("GetProcAddress");
835 if (!isdll)
836 addKernelImport("ExitProcess");
837 addKernelImport("VirtualProtect");
838 }
839
processImports2(unsigned myimport,unsigned)840 void PeFile::processImports2(unsigned myimport, unsigned) // pass 2
841 {
842 COMPILE_TIME_ASSERT(sizeof(import_desc) == 20);
843
844 ilinker->relocate_import(myimport);
845 int len;
846 oimpdlls = ilinker->getLoader(&len);
847 assert(len == (int) soimpdlls);
848 //OutputFile::dump("x1.imp", oimpdlls, soimpdlls);
849 }
850
851 template <typename LEXX, typename ord_mask_t>
processImports0(ord_mask_t ord_mask)852 unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
853 {
854 unsigned dllnum = 0;
855 unsigned const take = IDSIZE(PEDIR_IMPORT);
856 unsigned const skip = IDADDR(PEDIR_IMPORT);
857 import_desc *im = (import_desc*)ibuf.subref("bad import %#x", skip, take);
858 import_desc * const im_save = im;
859 if (IDADDR(PEDIR_IMPORT))
860 {
861 for (;; ++dllnum, ++im) {
862 unsigned const skip2 = ptr_diff(im, ibuf);
863 (void)ibuf.subref("bad import %#x", skip2, sizeof(*im));
864 if (!im->dllname)
865 break;
866 }
867 im = im_save;
868 }
869
870 struct udll
871 {
872 const upx_byte *name;
873 const upx_byte *shname;
874 unsigned ordinal;
875 unsigned iat;
876 LEXX *lookupt;
877 unsigned original_position;
878 bool isk32;
879
880 static int __acc_cdecl_qsort compare(const void *p1, const void *p2)
881 {
882 const udll *u1 = * (const udll * const *) p1;
883 const udll *u2 = * (const udll * const *) p2;
884 if (u1->isk32) return -1;
885 if (u2->isk32) return 1;
886 if (!*u1->lookupt) return 1;
887 if (!*u2->lookupt) return -1;
888 int rc = strcasecmp(u1->name,u2->name);
889 if (rc) return rc;
890 if (u1->ordinal) return -1;
891 if (u2->ordinal) return 1;
892 if (!u1->shname) return 1;
893 if (!u2->shname) return -1;
894 rc = (int) (upx_strlen(u1->shname) - upx_strlen(u2->shname));
895 if (rc) return rc;
896 return strcmp(u1->shname, u2->shname);
897 }
898 };
899
900 // +1 for dllnum=0
901 Array(struct udll, dlls, dllnum+1);
902 Array(struct udll *, idlls, dllnum+1);
903
904 soimport = 1024; // safety
905
906 unsigned ic;
907 for (ic = 0; dllnum && im->dllname; ic++, im++)
908 {
909 idlls[ic] = dlls + ic;
910 dlls[ic].name = ibuf.subref("bad dllname %#x", im->dllname, 1);
911 dlls[ic].shname = NULL;
912 dlls[ic].ordinal = 0;
913 dlls[ic].iat = im->iat;
914 unsigned const skip2 = (im->oft ? im->oft : im->iat);
915 dlls[ic].lookupt = (LEXX*)ibuf.subref("bad dll lookupt %#x", skip2, sizeof(LEXX));
916 dlls[ic].original_position = ic;
917 dlls[ic].isk32 = strcasecmp(kernelDll(), (const char*)dlls[ic].name) == 0;
918
919 soimport += strlen(dlls[ic].name) + 1 + 4;
920
921 for (IPTR_I(LEXX, tarr, dlls[ic].lookupt); *tarr; tarr += 1)
922 {
923 if (*tarr & ord_mask)
924 {
925 importbyordinal = true;
926 soimport += 2; // ordinal num: 2 bytes
927 dlls[ic].ordinal = *tarr & 0xffff;
928 }
929 else //it's an import by name
930 {
931 IPTR_I(const upx_byte, n, ibuf + *tarr + 2);
932 unsigned len = strlen(n);
933 soimport += len + 1;
934 if (dlls[ic].shname == NULL || len < strlen (dlls[ic].shname))
935 dlls[ic].shname = ibuf + *tarr + 2;
936 }
937 soimport++; // separator
938 }
939 }
940 oimport = New(upx_byte, soimport);
941 memset(oimport,0,soimport);
942
943 qsort(idlls,dllnum,sizeof (udll*),udll::compare);
944
945 info("Processing imports: %d DLLs", dllnum);
946
947 ilinker = new ImportLinker(sizeof(LEXX));
948 // create the new import table
949 addStubImports();
950
951 for (ic = 0; ic < dllnum; ic++)
952 {
953 if (idlls[ic]->isk32)
954 {
955 // for kernel32.dll we need to put all the imported
956 // ordinals into the output import table, as on
957 // some versions of windows GetProcAddress does not resolve them
958 if (strcasecmp((const char*)idlls[ic]->name, "kernel32.dll"))
959 continue;
960 if (idlls[ic]->ordinal)
961 for (LEXX *tarr = idlls[ic]->lookupt; *tarr; tarr++)
962 if (*tarr & ord_mask)
963 {
964 ilinker->add(kernelDll(), *tarr & 0xffff);
965 kernel32ordinal = true;
966 }
967 }
968 else if (!ilinker->hasDll(idlls[ic]->name))
969 {
970 if (idlls[ic]->ordinal)
971 ilinker->add(idlls[ic]->name, idlls[ic]->ordinal);
972 else if (idlls[ic]->shname)
973 ilinker->add(idlls[ic]->name, idlls[ic]->shname);
974 else
975 throwInternalError("should not happen");
976 }
977 }
978
979 soimpdlls = ilinker->build();
980
981 Interval names(ibuf),iats(ibuf),lookups(ibuf);
982
983 // create the preprocessed data
984 upx_byte *ppi = oimport; // preprocessed imports
985 for (ic = 0; ic < dllnum; ic++)
986 {
987 LEXX *tarr = idlls[ic]->lookupt;
988 #if 0 && ENABLE_THIS_AND_UNCOMPRESSION_WILL_BREAK // FIXME
989 if (!*tarr) // no imports from this dll
990 continue;
991 #endif
992 set_le32(ppi, ilinker->getAddress(idlls[ic]->name));
993 set_le32(ppi+4,idlls[ic]->iat - rvamin);
994 ppi += 8;
995 for (; *tarr; tarr++)
996 if (*tarr & ord_mask)
997 {
998 unsigned ord = *tarr & 0xffff;
999 if (idlls[ic]->isk32 && kernel32ordinal)
1000 {
1001 *ppi++ = 0xfe; // signed + odd parity
1002 set_le32(ppi, ilinker->getAddress(idlls[ic]->name, ord));
1003 ppi += 4;
1004 }
1005 else
1006 {
1007 *ppi++ = 0xff;
1008 set_le16(ppi, ord);
1009 ppi += 2;
1010 }
1011 }
1012 else
1013 {
1014 *ppi++ = 1;
1015 unsigned const skip2 = 2+ *tarr;
1016 unsigned const take2 = 1+ strlen(ibuf.subref("bad import name %#x", skip2, 1));
1017 memcpy(ppi,ibuf.subref("bad import name %#x", skip2, take2), take2);
1018 ppi += take2;
1019 names.add(*tarr, 2+ take2);
1020 }
1021 ppi++;
1022
1023 unsigned esize = ptr_diff((char *)tarr, (char *)idlls[ic]->lookupt);
1024 lookups.add(idlls[ic]->lookupt,esize);
1025 if (ptr_diff(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1), (char *)idlls[ic]->lookupt))
1026 {
1027 memcpy(ibuf.subref("bad import name %#x", idlls[ic]->iat, esize), idlls[ic]->lookupt, esize);
1028 iats.add(idlls[ic]->iat,esize);
1029 }
1030 names.add(idlls[ic]->name,strlen(idlls[ic]->name) + 1 + 1);
1031 }
1032 ppi += 4;
1033 assert(ppi < oimport+soimport);
1034 soimport = ptr_diff(ppi,oimport);
1035
1036 if (soimport == 4)
1037 soimport = 0;
1038
1039 //OutputFile::dump("x0.imp", oimport, soimport);
1040
1041 unsigned ilen = 0;
1042 names.flatten();
1043 if (names.ivnum > 1)
1044 {
1045 // The area occupied by the dll and imported names is not continuous
1046 // so to still support uncompression, I can't zero the iat area.
1047 // This decreases compression ratio, so FIXME somehow.
1048 infoWarning("can't remove unneeded imports");
1049 ilen += sizeof(import_desc) * dllnum;
1050 #if defined(DEBUG)
1051 if (opt->verbose > 3)
1052 names.dump();
1053 #endif
1054 // do some work for the unpacker
1055 im = im_save;
1056 for (ic = 0; ic < dllnum; ic++, im++)
1057 {
1058 memset(im,FILLVAL,sizeof(*im));
1059 im->dllname = ptr_diff(dlls[idlls[ic]->original_position].name,ibuf);
1060 }
1061 }
1062 else
1063 {
1064 iats.add(im_save,sizeof(import_desc) * dllnum);
1065 // zero unneeded data
1066 iats.clear();
1067 lookups.clear();
1068 }
1069 names.clear();
1070
1071 iats.add(&names);
1072 iats.add(&lookups);
1073 iats.flatten();
1074 for (ic = 0; ic < iats.ivnum; ic++)
1075 ilen += iats.ivarr[ic].len;
1076
1077 info("Imports: original size: %u bytes, preprocessed size: %u bytes",ilen,soimport);
1078 return names.ivnum == 1 ? names.ivarr[0].start : 0;
1079 }
1080
1081 /*************************************************************************
1082 // export handling
1083 **************************************************************************/
1084
Export(char * _base)1085 PeFile::Export::Export(char *_base) : base(_base), iv(_base)
1086 {
1087 COMPILE_TIME_ASSERT(sizeof(export_dir_t) == 40)
1088 COMPILE_TIME_ASSERT_ALIGNED1(export_dir_t)
1089 ename = functionptrs = ordinals = NULL;
1090 names = NULL;
1091 memset(&edir,0,sizeof(edir));
1092 size = 0;
1093 }
1094
~Export()1095 PeFile::Export::~Export()
1096 {
1097 free(ename);
1098 delete [] functionptrs;
1099 delete [] ordinals;
1100 if (names) {
1101 unsigned const limit = edir.names + edir.functions;
1102 for (unsigned ic = 0; ic < limit; ic++)
1103 if (names[ic]) free(names[ic]); // allocated by strdup()
1104 delete [] names;
1105 }
1106 }
1107
convert(unsigned eoffs,unsigned esize)1108 void PeFile::Export::convert(unsigned eoffs,unsigned esize)
1109 {
1110 memcpy(&edir,base + eoffs,sizeof(export_dir_t));
1111 size = sizeof(export_dir_t);
1112 iv.add(eoffs,size);
1113
1114 if (eoffs + esize <= (unsigned)edir.name) {
1115 char msg[50]; snprintf(msg, sizeof(msg),
1116 "bad export directory name RVA %#x", (unsigned)edir.name);
1117 throwInternalError(msg);
1118 }
1119 unsigned len = strlen(base + edir.name) + 1;
1120 ename = strdup(base + edir.name);
1121 size += len;
1122 iv.add(edir.name,len);
1123
1124 len = 4 * edir.functions;
1125 functionptrs = New(char, len + 1);
1126 memcpy(functionptrs,base + edir.addrtable,len);
1127 size += len;
1128 iv.add(edir.addrtable,len);
1129
1130 unsigned ic;
1131 names = New(char *, edir.names + edir.functions + 1);
1132 for (ic = 0; ic < edir.names; ic++)
1133 {
1134 char *n = base + get_le32(base + edir.nameptrtable + ic * 4);
1135 len = strlen(n) + 1;
1136 names[ic] = strdup(n);
1137 size += len;
1138 iv.add(get_le32(base + edir.nameptrtable + ic * 4),len);
1139 }
1140 iv.add(edir.nameptrtable,4 * edir.names);
1141 size += 4 * edir.names;
1142
1143 LE32 *fp = (LE32*) functionptrs;
1144 // export forwarders
1145 for (ic = 0; ic < edir.functions; ic++)
1146 if (fp[ic] >= eoffs && fp[ic] < eoffs + esize)
1147 {
1148 char *forw = base + fp[ic];
1149 len = strlen(forw) + 1;
1150 iv.add(forw,len);
1151 size += len;
1152 names[ic + edir.names] = strdup(forw);
1153 }
1154 else
1155 names[ic + edir.names] = NULL;
1156
1157 len = 2 * edir.names;
1158 ordinals = New(char, len + 1);
1159 memcpy(ordinals,base + edir.ordinaltable,len);
1160 size += len;
1161 iv.add(edir.ordinaltable,len);
1162 iv.flatten();
1163 if (iv.ivnum == 1)
1164 iv.clear();
1165 #if defined(DEBUG)
1166 else
1167 iv.dump();
1168 #endif
1169 }
1170
build(char * newbase,unsigned newoffs)1171 void PeFile::Export::build(char *newbase, unsigned newoffs)
1172 {
1173 char * const functionp = newbase + sizeof(edir);
1174 char * const namep = functionp + 4 * edir.functions;
1175 char * const ordinalp = namep + 4 * edir.names;
1176 char * const enamep = ordinalp + 2 * edir.names;
1177 char * exports = enamep + strlen(ename) + 1;
1178
1179 edir.addrtable = newoffs + ptr_diff(functionp, newbase);
1180 edir.ordinaltable = newoffs + ptr_diff(ordinalp, newbase);
1181 memcpy(ordinalp,ordinals,2 * edir.names);
1182
1183 edir.name = newoffs + ptr_diff(enamep, newbase);
1184 strcpy(enamep,ename);
1185 edir.nameptrtable = newoffs + ptr_diff(namep, newbase);
1186 unsigned ic;
1187 for (ic = 0; ic < edir.names; ic++)
1188 {
1189 strcpy(exports,names[ic]);
1190 set_le32(namep + 4 * ic,newoffs + ptr_diff(exports, newbase));
1191 exports += strlen(exports) + 1;
1192 }
1193
1194 memcpy(functionp,functionptrs,4 * edir.functions);
1195 for (ic = 0; ic < edir.functions; ic++)
1196 if (names[edir.names + ic])
1197 {
1198 strcpy(exports,names[edir.names + ic]);
1199 set_le32(functionp + 4 * ic,newoffs + ptr_diff(exports, newbase));
1200 exports += strlen(exports) + 1;
1201 }
1202
1203 memcpy(newbase,&edir,sizeof(edir));
1204 assert(exports - newbase == (int) size);
1205 }
1206
processExports(Export * xport)1207 void PeFile::processExports(Export *xport) // pass1
1208 {
1209 soexport = ALIGN_UP(IDSIZE(PEDIR_EXPORT),4u);
1210 if (soexport == 0)
1211 return;
1212 if (!isdll && opt->win32_pe.compress_exports)
1213 {
1214 infoWarning("exports compressed, --compress-exports=0 might be needed");
1215 soexport = 0;
1216 return;
1217 }
1218 xport->convert(IDADDR(PEDIR_EXPORT),IDSIZE(PEDIR_EXPORT));
1219 soexport = ALIGN_UP(xport->getsize(), 4u);
1220 oexport = New(upx_byte, soexport);
1221 memset(oexport, 0, soexport);
1222 }
1223
processExports(Export * xport,unsigned newoffs)1224 void PeFile::processExports(Export *xport,unsigned newoffs) // pass2
1225 {
1226 if (soexport)
1227 xport->build((char*) oexport,newoffs);
1228 }
1229
1230
1231 /*************************************************************************
1232 // TLS handling
1233 **************************************************************************/
1234
1235 // thanks for theowl for providing me some docs, so that now I understand
1236 // what I'm doing here :)
1237
1238 // 1999-10-17: this was tricky to find:
1239 // when the fixup records and the tls area are on the same page, then
1240 // the tls area is not relocated, because the relocation is done by
1241 // the virtual memory manager only for pages which are not yet loaded.
1242 // of course it was impossible to debug this ;-)
1243
1244 template <>
1245 struct PeFile::tls_traits<LE32>
1246 {
1247 __packed_struct(tls)
1248 LE32 datastart; // VA tls init data start
1249 LE32 dataend; // VA tls init data end
1250 LE32 tlsindex; // VA tls index
1251 LE32 callbacks; // VA tls callbacks
1252 char _[8]; // zero init, characteristics
1253 __packed_struct_end()
1254
1255 static const unsigned sotls = 24;
1256 static const unsigned cb_size = 4;
1257 typedef unsigned cb_value_t;
1258 static const unsigned reloc_type = 3;
1259 static const int tls_handler_offset_reloc = 4;
1260 };
1261
1262 template <>
1263 struct PeFile::tls_traits<LE64>
1264 {
1265 __packed_struct(tls)
1266 LE64 datastart; // VA tls init data start
1267 LE64 dataend; // VA tls init data end
1268 LE64 tlsindex; // VA tls index
1269 LE64 callbacks; // VA tls callbacks
1270 char _[8]; // zero init, characteristics
1271 __packed_struct_end()
1272
1273 static const unsigned sotls = 40;
1274 static const unsigned cb_size = 8;
1275 typedef upx_uint64_t cb_value_t;
1276 static const unsigned reloc_type = 10;
1277 static const int tls_handler_offset_reloc = -1; // no need to relocate
1278 };
1279
1280 template <typename LEXX>
processTls1(Interval * iv,typename tls_traits<LEXX>::cb_value_t imagebase,unsigned imagesize)1281 void PeFile::processTls1(Interval *iv,
1282 typename tls_traits<LEXX>::cb_value_t imagebase,
1283 unsigned imagesize) // pass 1
1284 {
1285 typedef typename tls_traits<LEXX>::tls tls;
1286 typedef typename tls_traits<LEXX>::cb_value_t cb_value_t;
1287 const unsigned cb_size = tls_traits<LEXX>::cb_size;
1288
1289 COMPILE_TIME_ASSERT(sizeof(tls) == tls_traits<LEXX>::sotls)
1290 COMPILE_TIME_ASSERT_ALIGNED1(tls)
1291
1292 unsigned const take = ALIGN_UP(IDSIZE(PEDIR_TLS),4u);
1293 sotls = take;
1294 if (!sotls)
1295 return;
1296
1297 unsigned const skip = IDADDR(PEDIR_TLS);
1298 const tls * const tlsp = (const tls*)ibuf.subref("bad tls %#x", skip, sizeof(tls));
1299
1300 // note: TLS callbacks are not implemented in Windows 95/98/ME
1301 if (tlsp->callbacks)
1302 {
1303 if (tlsp->callbacks < imagebase)
1304 throwCantPack("invalid TLS callback");
1305 else if (tlsp->callbacks - imagebase + 4 >= imagesize)
1306 throwCantPack("invalid TLS callback");
1307 cb_value_t v = *(LEXX*)ibuf.subref("bad TLS %#x", (tlsp->callbacks - imagebase), sizeof(LEXX));
1308
1309 if(v != 0)
1310 {
1311 //count number of callbacks, just for information string - Stefan Widmann
1312 unsigned num_callbacks = 0;
1313 unsigned callback_offset = 0;
1314 while (*(LEXX*)ibuf.subref("bad TLS %#x",
1315 tlsp->callbacks - imagebase + callback_offset, sizeof(LEXX)))
1316 {
1317 //increment number of callbacks
1318 num_callbacks++;
1319 callback_offset += cb_size;
1320 }
1321 info("TLS: %u callback(s) found, adding TLS callback handler", num_callbacks);
1322 //set flag to include necessary sections in loader
1323 use_tls_callbacks = true;
1324 //define linker symbols
1325 tlscb_ptr = tlsp->callbacks;
1326 }
1327 }
1328
1329 const unsigned tlsdatastart = tlsp->datastart - imagebase;
1330 const unsigned tlsdataend = tlsp->dataend - imagebase;
1331
1332 // now some ugly stuff: find the relocation entries in the tls data area
1333 unsigned const take2 = IDSIZE(PEDIR_RELOC);
1334 unsigned const skip2 = IDADDR(PEDIR_RELOC);
1335 Reloc rel(ibuf.subref("bad tls reloc %#x", skip2, take2), take2);
1336 unsigned pos,type;
1337 while (rel.next(pos,type))
1338 if (pos >= tlsdatastart && pos < tlsdataend)
1339 iv->add(pos,type);
1340
1341 sotls = sizeof(tls) + tlsdataend - tlsdatastart;
1342 // if TLS callbacks are used, we need two more {D|Q}WORDS at the end of the TLS
1343 // ... and those dwords should be correctly aligned
1344 if (use_tls_callbacks)
1345 sotls = ALIGN_UP(sotls, cb_size) + 2 * cb_size;
1346
1347 // the PE loader wants this stuff uncompressed
1348 otls = New(upx_byte, sotls);
1349 memset(otls,0,sotls);
1350 unsigned const take1 = sizeof(tls);
1351 unsigned const skip1 = IDADDR(PEDIR_TLS);
1352 memcpy(otls,ibuf.subref("bad tls %#x", skip1, take1), take1);
1353 // WARNING: this can acces data in BSS
1354 unsigned const take3 = sotls - sizeof(tls);
1355 memcpy(otls + sizeof(tls),ibuf.subref("bad tls %#x", tlsdatastart, take3), take3);
1356 tlsindex = tlsp->tlsindex - imagebase;
1357 //NEW: subtract two dwords if TLS callbacks are used - Stefan Widmann
1358 info("TLS: %u bytes tls data and %u relocations added",
1359 sotls - (unsigned) sizeof(tls) - (use_tls_callbacks ? 2 * cb_size : 0),iv->ivnum);
1360
1361 // makes sure tls index is zero after decompression
1362 if (tlsindex && tlsindex < imagesize)
1363 set_le32(ibuf.subref("bad tlsindex %#x", tlsindex, sizeof(unsigned)), 0);
1364 }
1365
1366 template <typename LEXX>
processTls2(Reloc * rel,const Interval * iv,unsigned newaddr,typename tls_traits<LEXX>::cb_value_t imagebase)1367 void PeFile::processTls2(Reloc *rel,const Interval *iv,unsigned newaddr,
1368 typename tls_traits<LEXX>::cb_value_t imagebase) // pass 2
1369 {
1370 typedef typename tls_traits<LEXX>::tls tls;
1371 typedef typename tls_traits<LEXX>::cb_value_t cb_value_t;
1372 const unsigned cb_size = tls_traits<LEXX>::cb_size;
1373 const unsigned reloc_type = tls_traits<LEXX>::reloc_type;
1374 const int tls_handler_offset_reloc = tls_traits<LEXX>::tls_handler_offset_reloc;
1375
1376 if (sotls == 0)
1377 return;
1378 // add new relocation entries
1379
1380 if __acc_cte(tls_handler_offset_reloc > 0)
1381 rel->add(tls_handler_offset + tls_handler_offset_reloc, reloc_type);
1382
1383 unsigned ic;
1384 //NEW: if TLS callbacks are used, relocate the VA of the callback chain, too - Stefan Widmann
1385 for (ic = 0; ic < (use_tls_callbacks ? 4 * cb_size : 3 * cb_size); ic += cb_size)
1386 rel->add(newaddr + ic, reloc_type);
1387
1388 tls * const tlsp = (tls*) otls;
1389 // now the relocation entries in the tls data area
1390 for (ic = 0; ic < iv->ivnum; ic += 4)
1391 {
1392 void *p = otls + iv->ivarr[ic].start - (tlsp->datastart - imagebase) + sizeof(tls);
1393 cb_value_t kc = *(LEXX*)(p);
1394 if (kc < tlsp->dataend && kc >= tlsp->datastart)
1395 {
1396 kc += newaddr + sizeof(tls) - tlsp->datastart;
1397 *(LEXX*)(p) = kc + imagebase;
1398 rel->add(kc,iv->ivarr[ic].len);
1399 }
1400 else
1401 rel->add(kc - imagebase,iv->ivarr[ic].len);
1402 }
1403
1404 const unsigned tls_data_size = tlsp->dataend - tlsp->datastart;
1405 tlsp->datastart = newaddr + sizeof(tls) + imagebase;
1406 tlsp->dataend = tlsp->datastart + tls_data_size;
1407
1408 //NEW: if we have TLS callbacks to handle, we create a pointer to the new callback chain - Stefan Widmann
1409 tlsp->callbacks = (use_tls_callbacks ? newaddr + sotls + imagebase - 2 * cb_size : 0);
1410
1411 if (use_tls_callbacks)
1412 {
1413 //set handler offset
1414 *(LEXX*)(otls + sotls - 2 * cb_size) = tls_handler_offset + imagebase;
1415 *(LEXX*)(otls + sotls - 1 * cb_size) = 0; // end of one-item list
1416 //add relocation for TLS handler offset
1417 rel->add(newaddr + sotls - 2 * cb_size, reloc_type);
1418 }
1419 }
1420
1421 /*************************************************************************
1422 // Load Configuration handling
1423 **************************************************************************/
1424
processLoadConf(Interval * iv)1425 void PeFile::processLoadConf(Interval *iv) // pass 1
1426 {
1427 if (IDSIZE(PEDIR_LOADCONF) == 0)
1428 return;
1429
1430 const unsigned lcaddr = IDADDR(PEDIR_LOADCONF);
1431 const upx_byte * const loadconf = ibuf.subref("bad loadconf %#x", lcaddr, 4);
1432 soloadconf = get_le32(loadconf);
1433 if (soloadconf == 0)
1434 return;
1435 static unsigned const MAX_SOLOADCONF = 256; // XXX FIXME: Why?
1436 if (soloadconf > MAX_SOLOADCONF)
1437 info("Load Configuration directory %u > %u", soloadconf, MAX_SOLOADCONF);
1438
1439 // if there were relocation entries referring to the load config table
1440 // then we need them for the copy of the table too
1441 unsigned const take = IDSIZE(PEDIR_RELOC);
1442 unsigned const skip = IDADDR(PEDIR_RELOC);
1443 Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
1444 unsigned pos,type;
1445 while (rel.next(pos, type))
1446 if (pos >= lcaddr && pos < lcaddr + soloadconf)
1447 {
1448 iv->add(pos - lcaddr, type);
1449 // printf("loadconf reloc detected: %x\n", pos);
1450 }
1451
1452 oloadconf = New(upx_byte, soloadconf);
1453 memcpy(oloadconf, loadconf, soloadconf);
1454 }
1455
processLoadConf(Reloc * rel,const Interval * iv,unsigned newaddr)1456 void PeFile::processLoadConf(Reloc *rel, const Interval *iv,
1457 unsigned newaddr) // pass2
1458 {
1459 // now we have the address of the new load config table
1460 // so we can create the new relocation entries
1461 for (unsigned ic = 0; ic < iv->ivnum; ic++)
1462 {
1463 rel->add(iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len);
1464 //printf("loadconf reloc added: %x %d\n",
1465 // iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len);
1466 }
1467 }
1468
1469 /*************************************************************************
1470 // resource handling
1471 **************************************************************************/
1472
1473 __packed_struct(PeFile::Resource::res_dir_entry)
1474 LE32 tnl; // Type | Name | Language id - depending on level
1475 LE32 child;
1476 __packed_struct_end()
1477
1478 __packed_struct(PeFile::Resource::res_dir)
1479 char _[12]; // flags, timedate, version
1480 LE16 namedentr;
1481 LE16 identr;
1482
Sizeof() const1483 unsigned Sizeof() const { return 16 + sizeof(res_dir_entry)*(namedentr + identr); }
1484 res_dir_entry entries[1];
1485 // it's usually safe to assume that every res_dir contains
1486 // at least one res_dir_entry - check() complains otherwise
1487 __packed_struct_end()
1488
1489 __packed_struct(PeFile::Resource::res_data)
1490 LE32 offset;
1491 LE32 size;
1492 char _[8]; // codepage, reserved
1493 __packed_struct_end()
1494
1495 struct PeFile::Resource::upx_rnode
1496 {
1497 unsigned id;
1498 upx_byte *name;
1499 upx_rnode *parent;
1500 };
1501
1502 struct PeFile::Resource::upx_rbranch : public PeFile::Resource::upx_rnode
1503 {
1504 unsigned nc;
1505 upx_rnode **children;
1506 res_dir data;
1507 };
1508
1509 struct PeFile::Resource::upx_rleaf : public PeFile::Resource::upx_rnode
1510 {
1511 upx_rleaf *next;
1512 unsigned newoffset;
1513 res_data data;
1514 };
1515
Resource(const upx_byte * ibufstart_,const upx_byte * ibufend_)1516 PeFile::Resource::Resource(const upx_byte *ibufstart_,
1517 const upx_byte *ibufend_) : root(NULL)
1518 {
1519 ibufstart = ibufstart_;
1520 ibufend = ibufend_;
1521 }
1522
Resource(const upx_byte * p,const upx_byte * ibufstart_,const upx_byte * ibufend_)1523 PeFile::Resource::Resource(const upx_byte *p,
1524 const upx_byte *ibufstart_,
1525 const upx_byte *ibufend_)
1526 {
1527 ibufstart = ibufstart_;
1528 ibufend = ibufend_;
1529 init(p);
1530 }
1531
~Resource()1532 PeFile::Resource::~Resource()
1533 {
1534 if (root) { destroy(root, 0); root = NULL; }
1535 }
1536
dirsize() const1537 unsigned PeFile::Resource::dirsize() const
1538 {
1539 return ALIGN_UP(dsize + ssize, 4u);
1540 }
1541
next()1542 bool PeFile::Resource::next()
1543 {
1544 // wow, builtin autorewind... :-)
1545 return (current = current ? current->next : head) != NULL;
1546 }
1547
itype() const1548 unsigned PeFile::Resource::itype() const
1549 {
1550 return current->parent->parent->id;
1551 }
1552
ntype() const1553 const upx_byte *PeFile::Resource::ntype() const
1554 {
1555 return current->parent->parent->name;
1556 }
1557
size() const1558 unsigned PeFile::Resource::size() const
1559 {
1560 return ALIGN_UP(current->data.size, 4u);
1561 }
1562
offs() const1563 unsigned PeFile::Resource::offs() const
1564 {
1565 return current->data.offset;
1566 }
1567
newoffs()1568 unsigned &PeFile::Resource::newoffs()
1569 {
1570 return current->newoffset;
1571 }
1572
dump() const1573 void PeFile::Resource::dump() const
1574 {
1575 dump(root,0);
1576 }
1577
iname() const1578 unsigned PeFile::Resource::iname() const
1579 {
1580 return current->parent->id;
1581 }
1582
nname() const1583 const upx_byte *PeFile::Resource::nname() const
1584 {
1585 return current->parent->name;
1586 }
1587
1588 /*
1589 unsigned ilang() const {return current->id;}
1590 const upx_byte *nlang() const {return current->name;}
1591 */
1592
init(const upx_byte * res)1593 void PeFile::Resource::init(const upx_byte *res)
1594 {
1595 COMPILE_TIME_ASSERT(sizeof(res_dir_entry) == 8)
1596 COMPILE_TIME_ASSERT(sizeof(res_dir) == 16 + 8)
1597 COMPILE_TIME_ASSERT(sizeof(res_data) == 16)
1598 COMPILE_TIME_ASSERT_ALIGNED1(res_dir_entry)
1599 COMPILE_TIME_ASSERT_ALIGNED1(res_dir)
1600 COMPILE_TIME_ASSERT_ALIGNED1(res_data)
1601
1602 start = res;
1603 root = head = current = NULL;
1604 dsize = ssize = 0;
1605 check((const res_dir*) start,0);
1606 root = convert(start,NULL,0);
1607 }
1608
check(const res_dir * node,unsigned level)1609 void PeFile::Resource::check(const res_dir *node,unsigned level)
1610 {
1611 ibufcheck(node, sizeof(*node));
1612 int ic = node->identr + node->namedentr;
1613 if (ic == 0)
1614 return;
1615 for (const res_dir_entry *rde = node->entries; --ic >= 0; rde++)
1616 {
1617 ibufcheck(rde, sizeof(*rde));
1618 if (((rde->child & 0x80000000) == 0) ^ (level == 2))
1619 throwCantPack("unsupported resource structure");
1620 else if (level != 2)
1621 check((const res_dir*) (start + (rde->child & 0x7fffffff)),level + 1);
1622 }
1623 }
1624
ibufcheck(const void * m,unsigned siz)1625 void PeFile::Resource::ibufcheck(const void *m, unsigned siz)
1626 {
1627 if (m < ibufstart || m > ibufend - siz)
1628 throwCantUnpack("corrupted resources");
1629 }
1630
convert(const void * rnode,upx_rnode * parent,unsigned level)1631 PeFile::Resource::upx_rnode *PeFile::Resource::convert(const void *rnode,
1632 upx_rnode *parent,
1633 unsigned level)
1634 {
1635 if (level == 3)
1636 {
1637 const res_data *node = ACC_STATIC_CAST(const res_data *, rnode);
1638 ibufcheck(node, sizeof(*node));
1639 upx_rleaf *leaf = new upx_rleaf;
1640 leaf->id = 0;
1641 leaf->name = NULL;
1642 leaf->parent = parent;
1643 leaf->next = head;
1644 leaf->newoffset = 0;
1645 leaf->data = *node;
1646
1647 head = leaf; // append node to a linked list for traversal
1648 dsize += sizeof(res_data);
1649 return leaf;
1650 }
1651
1652 const res_dir *node = ACC_STATIC_CAST(const res_dir *, rnode);
1653 ibufcheck(node, sizeof(*node));
1654 int ic = node->identr + node->namedentr;
1655 if (ic == 0)
1656 return NULL;
1657
1658 upx_rbranch *branch = new upx_rbranch;
1659 branch->id = 0;
1660 branch->name = NULL;
1661 branch->parent = parent;
1662 branch->nc = ic;
1663 branch->children = New(upx_rnode *, ic);
1664 branch->data = *node;
1665
1666 for (const res_dir_entry *rde = node->entries + ic - 1; --ic >= 0; rde--)
1667 {
1668 upx_rnode *child = convert(start + (rde->child & 0x7fffffff),branch,level + 1);
1669 xcheck(child);
1670 branch->children[ic] = child;
1671 child->id = rde->tnl;
1672 if (child->id & 0x80000000)
1673 {
1674 const upx_byte *p = start + (child->id & 0x7fffffff);
1675 ibufcheck(p, 2);
1676 const unsigned len = 2 + 2 * get_le16(p);
1677 ibufcheck(p, len);
1678 child->name = New(upx_byte, len);
1679 memcpy(child->name,p,len); // copy unicode string
1680 ssize += len; // size of unicode strings
1681 }
1682 }
1683 dsize += node->Sizeof();
1684 return branch;
1685 }
1686
build(const upx_rnode * node,unsigned & bpos,unsigned & spos,unsigned level)1687 void PeFile::Resource::build(const upx_rnode *node, unsigned &bpos,
1688 unsigned &spos, unsigned level)
1689 {
1690 if (level == 3)
1691 {
1692 if (bpos + sizeof(res_data) > dirsize())
1693 throwCantUnpack("corrupted resources");
1694
1695 res_data *l = (res_data*) (newstart + bpos);
1696 const upx_rleaf *leaf = (const upx_rleaf*) node;
1697 *l = leaf->data;
1698 if (leaf->newoffset)
1699 l->offset = leaf->newoffset;
1700 bpos += sizeof(*l);
1701 return;
1702 }
1703 if (bpos + sizeof(res_dir) > dirsize())
1704 throwCantUnpack("corrupted resources");
1705
1706 res_dir * const b = (res_dir*) (newstart + bpos);
1707 const upx_rbranch *branch = (const upx_rbranch*) node;
1708 *b = branch->data;
1709 bpos += b->Sizeof();
1710 res_dir_entry *be = b->entries;
1711 for (unsigned ic = 0; ic < branch->nc; ic++, be++)
1712 {
1713 xcheck(branch->children[ic]);
1714 be->tnl = branch->children[ic]->id;
1715 be->child = bpos + ((level < 2) ? 0x80000000 : 0);
1716
1717 const upx_byte *p;
1718 if ((p = branch->children[ic]->name) != 0)
1719 {
1720 be->tnl = spos + 0x80000000;
1721 if (spos + get_le16(p) * 2 + 2 > dirsize())
1722 throwCantUnpack("corrupted resources");
1723 memcpy(newstart + spos,p,get_le16(p) * 2 + 2);
1724 spos += get_le16(p) * 2 + 2;
1725 }
1726
1727 build(branch->children[ic],bpos,spos,level + 1);
1728 }
1729 }
1730
build()1731 upx_byte *PeFile::Resource::build()
1732 {
1733 newstart = New(upx_byte, dirsize());
1734 unsigned bpos = 0,spos = dsize;
1735 build(root,bpos,spos,0);
1736
1737 // dirsize() is 4 bytes aligned, so we may need to zero
1738 // up to 2 bytes to make valgrind happy
1739 while (spos < dirsize())
1740 newstart[spos++] = 0;
1741
1742 return newstart;
1743 }
1744
destroy(upx_rnode * node,unsigned level)1745 void PeFile::Resource::destroy(upx_rnode *node,unsigned level)
1746 {
1747 xcheck(node);
1748 if (level == 3)
1749 {
1750 upx_rleaf *leaf = ACC_STATIC_CAST(upx_rleaf *, node);
1751 delete [] leaf->name; leaf->name = NULL;
1752 delete leaf;
1753 }
1754 else
1755 {
1756 upx_rbranch *branch = ACC_STATIC_CAST(upx_rbranch *, node);
1757 delete [] branch->name; branch->name = NULL;
1758 for (int ic = branch->nc; --ic >= 0; )
1759 destroy(branch->children[ic], level + 1);
1760 delete [] branch->children; branch->children = NULL;
1761 delete branch;
1762 }
1763 }
1764
lame_print_unicode(const upx_byte * p)1765 static void lame_print_unicode(const upx_byte *p)
1766 {
1767 for (unsigned ic = 0; ic < get_le16(p); ic++)
1768 printf("%c",(char)p[ic * 2 + 2]);
1769 }
1770
dump(const upx_rnode * node,unsigned level) const1771 void PeFile::Resource::dump(const upx_rnode *node,unsigned level) const
1772 {
1773 if (level)
1774 {
1775 for (unsigned ic = 1; ic < level; ic++)
1776 printf("\t\t");
1777 if (node->name)
1778 lame_print_unicode(node->name);
1779 else
1780 printf("0x%x",node->id);
1781 printf("\n");
1782 }
1783 if (level == 3)
1784 return;
1785 const upx_rbranch * const branch = (const upx_rbranch *) node;
1786 for (unsigned ic = 0; ic < branch->nc; ic++)
1787 dump(branch->children[ic],level + 1);
1788 }
1789
clear(upx_byte * node,unsigned level,Interval * iv)1790 void PeFile::Resource::clear(upx_byte *node,unsigned level,Interval *iv)
1791 {
1792 if (level == 3)
1793 iv->add(node,sizeof (res_data));
1794 else
1795 {
1796 const res_dir * const rd = (res_dir*) node;
1797 const unsigned n = rd->identr + rd->namedentr;
1798 const res_dir_entry *rde = rd->entries;
1799 for (unsigned ic = 0; ic < n; ic++, rde++)
1800 clear(newstart + (rde->child & 0x7fffffff),level + 1,iv);
1801 iv->add(rd,rd->Sizeof());
1802 }
1803 }
1804
clear()1805 bool PeFile::Resource::clear()
1806 {
1807 newstart = const_cast<upx_byte*> (start);
1808 Interval iv(newstart);
1809 clear(newstart,0,&iv);
1810 iv.flatten();
1811 if (iv.ivnum == 1)
1812 iv.clear();
1813 #if defined(DEBUG)
1814 if (opt->verbose > 3)
1815 iv.dump();
1816 #endif
1817 return iv.ivnum == 1;
1818 }
1819
processResources(Resource * res,unsigned newaddr)1820 void PeFile::processResources(Resource *res,unsigned newaddr)
1821 {
1822 if (IDSIZE(PEDIR_RESOURCE) == 0)
1823 return;
1824 while (res->next())
1825 if (res->newoffs())
1826 res->newoffs() += newaddr;
1827 upx_byte *p = res->build();
1828 memcpy(oresources,p,res->dirsize());
1829 delete [] p;
1830 }
1831
match(unsigned itype,const unsigned char * ntype,unsigned iname,const unsigned char * nname,const char * keep)1832 static bool match(unsigned itype, const unsigned char *ntype,
1833 unsigned iname, const unsigned char *nname,
1834 const char *keep)
1835 {
1836 // format of string keep: type1[/name1],type2[/name2], ....
1837 // typex and namex can be string or number
1838 // hopefully resource names do not have '/' or ',' characters inside
1839
1840 struct helper
1841 {
1842 static bool match(unsigned num, const unsigned char *unistr,
1843 const char *mkeep)
1844 {
1845 if (!unistr)
1846 return (unsigned) atoi(mkeep) == num;
1847
1848 unsigned ic;
1849 for (ic = 0; ic < get_le16(unistr); ic++)
1850 if (unistr[2 + ic * 2] != (unsigned char) mkeep[ic])
1851 return false;
1852 return mkeep[ic] == 0 || mkeep[ic] == ',' || mkeep[ic] == '/';
1853 }
1854 };
1855
1856 // FIXME this comparison is not too exact
1857 for (;;)
1858 {
1859 char const *delim1 = strchr(keep, '/');
1860 char const *delim2 = strchr(keep, ',');
1861 if (helper::match(itype, ntype, keep))
1862 {
1863 if (!delim1)
1864 return true;
1865 if (delim2 && delim2 < delim1)
1866 return true;
1867 if (helper::match(iname, nname, delim1 + 1))
1868 return true;
1869 }
1870
1871 if (delim2 == NULL)
1872 break;
1873 keep = delim2 + 1;
1874 }
1875 return false;
1876 }
1877
processResources(Resource * res)1878 void PeFile::processResources(Resource *res)
1879 {
1880 const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
1881 if ((soresources = IDSIZE(PEDIR_RESOURCE)) == 0)
1882 return;
1883
1884 // setup default options for resource compression
1885 if (opt->win32_pe.compress_resources < 0)
1886 opt->win32_pe.compress_resources = true;
1887 if (!opt->win32_pe.compress_resources)
1888 {
1889 opt->win32_pe.compress_icons = false;
1890 for (int i = 0; i < RT_LAST; i++)
1891 opt->win32_pe.compress_rt[i] = false;
1892 }
1893 if (opt->win32_pe.compress_rt[RT_STRING] < 0)
1894 {
1895 // by default, don't compress RT_STRINGs of screensavers (".scr")
1896 opt->win32_pe.compress_rt[RT_STRING] = true;
1897 if (fn_has_ext(fi->getName(),"scr"))
1898 opt->win32_pe.compress_rt[RT_STRING] = false;
1899 }
1900
1901 res->init(ibuf.subref("bad res %#x", vaddr, 1));
1902
1903 for (soresources = res->dirsize(); res->next(); soresources += 4 + res->size())
1904 ;
1905 oresources = New(upx_byte, soresources);
1906 upx_byte *ores = oresources + res->dirsize();
1907
1908 char *keep_icons = NULL; // icon ids in the first icon group
1909 unsigned iconsin1stdir = 0;
1910 if (opt->win32_pe.compress_icons == 2)
1911 while (res->next()) // there is no rewind() in Resource
1912 if (res->itype() == RT_GROUP_ICON && iconsin1stdir == 0)
1913 {
1914 iconsin1stdir = get_le16(ibuf.subref("bad resoff %#x", res->offs() + 4, 2));
1915 keep_icons = New(char, 1 + iconsin1stdir * 9);
1916 *keep_icons = 0;
1917 for (unsigned ic = 0; ic < iconsin1stdir; ic++)
1918 upx_snprintf(keep_icons + strlen(keep_icons), 9, "3/%u,",
1919 get_le16(ibuf.subref("bad resoff %#x", res->offs() + 6 + ic * 14 + 12, 2)));
1920 if (*keep_icons)
1921 keep_icons[strlen(keep_icons) - 1] = 0;
1922 }
1923
1924 // the icon id which should not be compressed when compress_icons == 1
1925 unsigned first_icon_id = (unsigned) -1;
1926 if (opt->win32_pe.compress_icons == 1)
1927 while (res->next())
1928 if (res->itype() == RT_GROUP_ICON && first_icon_id == (unsigned) -1)
1929 first_icon_id = get_le16(ibuf.subref("bad resoff %#x", res->offs() + 6 + 12, 2));
1930
1931 bool compress_icon = opt->win32_pe.compress_icons > 1;
1932 bool compress_idir = opt->win32_pe.compress_icons == 3;
1933
1934 // some statistics
1935 unsigned usize = 0;
1936 unsigned csize = 0;
1937 unsigned unum = 0;
1938 unsigned cnum = 0;
1939
1940 while (res->next())
1941 {
1942 const unsigned rtype = res->itype();
1943 bool do_compress = true;
1944 if (!opt->win32_pe.compress_resources)
1945 do_compress = false;
1946 else if (rtype == RT_ICON) // icon
1947 {
1948 if (opt->win32_pe.compress_icons == 0)
1949 do_compress = false;
1950 else if (opt->win32_pe.compress_icons == 1)
1951 if ((first_icon_id == (unsigned) -1
1952 || first_icon_id == res->iname()))
1953 do_compress = compress_icon;
1954 }
1955 else if (rtype == RT_GROUP_ICON) // icon directory
1956 do_compress = compress_idir && opt->win32_pe.compress_icons;
1957 else if (rtype > 0 && rtype < RT_LAST)
1958 do_compress = opt->win32_pe.compress_rt[rtype] ? true : false;
1959
1960 if (keep_icons)
1961 do_compress &= !match(res->itype(), res->ntype(), res->iname(),
1962 res->nname(), keep_icons);
1963 do_compress &= !match(res->itype(), res->ntype(), res->iname(),
1964 res->nname(), "TYPELIB,REGISTRY,16");
1965 do_compress &= !match(res->itype(), res->ntype(), res->iname(),
1966 res->nname(), opt->win32_pe.keep_resource);
1967
1968 if (do_compress)
1969 {
1970 csize += res->size();
1971 cnum++;
1972 continue;
1973 }
1974
1975 usize += res->size();
1976 unum++;
1977
1978 set_le32(ores,res->offs()); // save original offset
1979 ores += 4;
1980 unsigned const take = res->size();
1981 ICHECK(ibuf + res->offs(), take);
1982 memcpy(ores, ibuf.subref("bad resoff %#x", res->offs(), take), take);
1983 ibuf.fill(res->offs(), take, FILLVAL);
1984 res->newoffs() = ptr_diff(ores,oresources);
1985 if (rtype == RT_ICON && opt->win32_pe.compress_icons == 1)
1986 compress_icon = true;
1987 else if (rtype == RT_GROUP_ICON)
1988 {
1989 if (opt->win32_pe.compress_icons == 1)
1990 {
1991 icondir_offset = 4 + ptr_diff(ores,oresources);
1992 icondir_count = get_le16(oresources + icondir_offset);
1993 set_le16(oresources + icondir_offset,1);
1994 }
1995 compress_idir = true;
1996 }
1997 ores += res->size();
1998 }
1999 soresources = ptr_diff(ores,oresources);
2000
2001 delete[] keep_icons;
2002 if (!res->clear())
2003 {
2004 // The area occupied by the resource directory is not continuous
2005 // so to still support uncompression, I can't zero this area.
2006 // This decreases compression ratio, so FIXME somehow.
2007 infoWarning("can't remove unneeded resource directory");
2008 }
2009 info("Resources: compressed %u (%u bytes), not compressed %u (%u bytes)",cnum,csize,unum,usize);
2010 }
2011
2012
virta2objnum(unsigned addr,pe_section_t * sect,unsigned objs)2013 unsigned PeFile::virta2objnum(unsigned addr,pe_section_t *sect,unsigned objs)
2014 {
2015 unsigned ic;
2016 for (ic = 0; ic < objs; ic++)
2017 {
2018 if (sect->vaddr <= addr && sect->vaddr + sect->vsize > addr)
2019 return ic;
2020 sect++;
2021 }
2022 //throwCantPack("virta2objnum() failed");
2023 return ic;
2024 }
2025
2026
tryremove(unsigned vaddr,unsigned objs)2027 unsigned PeFile::tryremove (unsigned vaddr,unsigned objs)
2028 {
2029 unsigned ic = virta2objnum(vaddr,isection,objs);
2030 if (ic && ic == objs - 1)
2031 {
2032 //fprintf(stderr,"removed section: %d size: %lx\n",ic,(long)isection[ic].size);
2033 info("removed section: %d size: 0x%lx",ic,(long)isection[ic].size);
2034 objs--;
2035 }
2036 return objs;
2037 }
2038
2039
stripDebug(unsigned overlaystart)2040 unsigned PeFile::stripDebug(unsigned overlaystart)
2041 {
2042 if (IDADDR(PEDIR_DEBUG) == 0)
2043 return overlaystart;
2044
2045 __packed_struct(debug_dir_t)
2046 char _[16]; // flags, time/date, version, type
2047 LE32 size;
2048 char __[4]; // rva
2049 LE32 fpos;
2050 __packed_struct_end()
2051
2052 COMPILE_TIME_ASSERT(sizeof(debug_dir_t) == 28)
2053 COMPILE_TIME_ASSERT_ALIGNED1(debug_dir_t)
2054 COMPILE_TIME_ASSERT(sizeof(((debug_dir_t*)0)->_) == 16)
2055 COMPILE_TIME_ASSERT(sizeof(((debug_dir_t*)0)->__) == 4)
2056
2057 unsigned const take = IDSIZE(PEDIR_DEBUG);
2058 unsigned const skip = IDADDR(PEDIR_DEBUG);
2059 const debug_dir_t *dd = (const debug_dir_t*)ibuf.subref("bad debug %#x", skip, take);
2060 for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(debug_dir_t); ic++, dd++)
2061 if (overlaystart == dd->fpos)
2062 overlaystart += dd->size;
2063 ibuf.fill(IDADDR(PEDIR_DEBUG), IDSIZE(PEDIR_DEBUG), FILLVAL);
2064 return overlaystart;
2065 }
2066
2067
2068 /*************************************************************************
2069 // pack
2070 **************************************************************************/
2071
readSectionHeaders(unsigned objs,unsigned sizeof_ih)2072 void PeFile::readSectionHeaders(unsigned objs, unsigned sizeof_ih)
2073 {
2074 if (!objs) {
2075 return;
2076 }
2077 isection = New(pe_section_t, objs);
2078 if (file_size < (off_t)(pe_offset + sizeof_ih + sizeof(pe_section_t)*objs)) {
2079 char buf[32]; snprintf(buf, sizeof(buf), "too many sections %d", objs);
2080 throwCantPack(buf);
2081 }
2082 fi->seek(pe_offset+sizeof_ih,SEEK_SET);
2083 fi->readx(isection,sizeof(pe_section_t)*objs);
2084 rvamin = isection[0].vaddr;
2085 unsigned const rvalast = isection[-1+ objs].vsize + isection[-1+ objs].vaddr;
2086 for (unsigned j=0; j < objs; ++j) { // expect: first is min, last is max
2087 unsigned lo = isection[j].vaddr, hi = isection[j].vsize + lo;
2088 if (hi < lo) { // this checks first and last sections, too!
2089 char buf[64]; snprintf(buf, sizeof(buf),
2090 "bad section[%d] wrap-around %#x %#x", j, lo, hi - lo);
2091 throwCantPack(buf);
2092 }
2093 if (lo < rvamin) {
2094 char buf[64]; snprintf(buf, sizeof(buf),
2095 "bad section .rva [%d] %#x < [0] %#x", j, lo, rvamin);
2096 throwCantPack(buf);
2097 }
2098 if (rvalast < hi) {
2099 char buf[80]; snprintf(buf, sizeof(buf),
2100 "bad section .rva+.vsize [%d] %#x > [%d] %#x", j, hi,
2101 (-1+ objs), rvalast);
2102 throwCantPack(buf);
2103 }
2104 }
2105
2106 infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs);
2107 }
2108
checkHeaderValues(unsigned subsystem,unsigned mask,unsigned ih_entry,unsigned ih_filealign)2109 void PeFile::checkHeaderValues(unsigned subsystem, unsigned mask,
2110 unsigned ih_entry, unsigned ih_filealign)
2111 {
2112 if ((1u << subsystem) & ~mask)
2113 {
2114 char buf[100];
2115 upx_snprintf(buf, sizeof(buf), "PE: subsystem %u is not supported",
2116 subsystem);
2117 throwCantPack(buf);
2118 }
2119 //check CLR Runtime Header directory entry
2120 if (IDSIZE(PEDIR_COMRT))
2121 throwCantPack(".NET files are not yet supported");
2122
2123 if (memcmp(isection[0].name,"UPX",3) == 0)
2124 throwAlreadyPackedByUPX();
2125
2126 if (!opt->force && IDSIZE(15))
2127 throwCantPack("file is possibly packed/protected (try --force)");
2128
2129 if (ih_entry && ih_entry < rvamin)
2130 throwCantPack("run a virus scanner on this file!");
2131
2132 if (ih_filealign < 0x200)
2133 throwCantPack("filealign < 0x200 is not yet supported");
2134 }
2135
handleStripRelocs(upx_uint64_t ih_imagebase,upx_uint64_t default_imagebase,unsigned dllflags)2136 unsigned PeFile::handleStripRelocs(upx_uint64_t ih_imagebase,
2137 upx_uint64_t default_imagebase,
2138 unsigned dllflags)
2139 {
2140 if (dllflags & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE)
2141 opt->win32_pe.strip_relocs = false;
2142 else if (isdll) //do never strip relocations from DLLs
2143 opt->win32_pe.strip_relocs = false;
2144 else if (opt->win32_pe.strip_relocs < 0)
2145 opt->win32_pe.strip_relocs = (ih_imagebase >= default_imagebase);
2146 if (opt->win32_pe.strip_relocs)
2147 {
2148 if (ih_imagebase < default_imagebase)
2149 throwCantPack("--strip-relocs is not allowed with this imagebase");
2150 else
2151 return RELOCS_STRIPPED;
2152 }
2153 return 0;
2154 }
2155
readSections(unsigned objs,unsigned usize,unsigned ih_filealign,unsigned ih_datasize)2156 unsigned PeFile::readSections(unsigned objs, unsigned usize,
2157 unsigned ih_filealign, unsigned ih_datasize)
2158 {
2159 const unsigned xtrasize = UPX_MAX(ih_datasize, 65536u) + IDSIZE(PEDIR_IMPORT)
2160 + IDSIZE(PEDIR_BOUNDIM) + IDSIZE(PEDIR_IAT) + IDSIZE(PEDIR_DELAYIMP)
2161 + IDSIZE(PEDIR_RELOC);
2162 ibuf.alloc(usize + xtrasize);
2163
2164 // BOUND IMPORT support. FIXME: is this ok?
2165 fi->seek(0,SEEK_SET);
2166 fi->readx(ibuf,isection[0].rawdataptr);
2167
2168 //Interval holes(ibuf);
2169
2170 unsigned ic,jc,overlaystart = 0;
2171 ibuf.clear(0, usize);
2172 for (ic = jc = 0; ic < objs; ic++)
2173 {
2174 if (isection[ic].rawdataptr && overlaystart < isection[ic].rawdataptr + isection[ic].size)
2175 overlaystart = ALIGN_UP(isection[ic].rawdataptr + isection[ic].size,ih_filealign);
2176 if (isection[ic].vsize == 0)
2177 isection[ic].vsize = isection[ic].size;
2178 if ((isection[ic].flags & PEFL_BSS) || isection[ic].rawdataptr == 0
2179 || (isection[ic].flags & PEFL_INFO))
2180 {
2181 //holes.add(isection[ic].vaddr,isection[ic].vsize);
2182 continue;
2183 }
2184 if (isection[ic].vaddr + isection[ic].size > usize)
2185 throwCantPack("section size problem");
2186 if (!isrtm && ((isection[ic].flags & (PEFL_WRITE|PEFL_SHARED))
2187 == (PEFL_WRITE|PEFL_SHARED)))
2188 if (!opt->force)
2189 throwCantPack("writable shared sections not supported (try --force)");
2190 if (jc && isection[ic].rawdataptr - jc > ih_filealign && !opt->force)
2191 throwCantPack("superfluous data between sections (try --force)");
2192 fi->seek(isection[ic].rawdataptr,SEEK_SET);
2193 jc = isection[ic].size;
2194 if (jc > isection[ic].vsize)
2195 jc = isection[ic].vsize;
2196 if (isection[ic].vsize == 0) // hack for some tricky programs - may this break other progs?
2197 jc = isection[ic].vsize = isection[ic].size;
2198 if (isection[ic].vaddr + jc > ibuf.getSize())
2199 throwInternalError("buffer too small 1");
2200 fi->readx(ibuf.subref("bad section %#x", isection[ic].vaddr, jc), jc);
2201 jc += isection[ic].rawdataptr;
2202 }
2203 return overlaystart;
2204 }
2205
callCompressWithFilters(Filter & ft,int filter_strategy,unsigned ih_codebase)2206 void PeFile::callCompressWithFilters(Filter &ft, int filter_strategy, unsigned ih_codebase)
2207 {
2208 compressWithFilters(&ft, 2048, NULL_cconf, filter_strategy,
2209 ih_codebase, rvamin, 0, NULL, 0);
2210 }
2211
callProcessRelocs(Reloc & rel,unsigned & ic)2212 void PeFile::callProcessRelocs(Reloc &rel, unsigned &ic)
2213 {
2214 // wince wants relocation data at the beginning of a section
2215 PeFile::processRelocs(&rel);
2216 ODADDR(PEDIR_RELOC) = soxrelocs ? ic : 0;
2217 ODSIZE(PEDIR_RELOC) = soxrelocs;
2218 ic += soxrelocs;
2219 }
2220
callProcessResources(Resource & res,unsigned & ic)2221 void PeFile::callProcessResources(Resource &res, unsigned &ic)
2222 {
2223 if (soresources)
2224 processResources(&res,ic);
2225 ODADDR(PEDIR_RESOURCE) = soresources ? ic : 0;
2226 ODSIZE(PEDIR_RESOURCE) = soresources;
2227 ic += soresources;
2228 }
2229
2230 template <typename LEXX, typename ht>
pack0(OutputFile * fo,ht & ih,ht & oh,unsigned subsystem_mask,upx_uint64_t default_imagebase,bool last_section_rsrc_only)2231 void PeFile::pack0(OutputFile *fo, ht &ih, ht &oh,
2232 unsigned subsystem_mask, upx_uint64_t default_imagebase,
2233 bool last_section_rsrc_only)
2234 {
2235 // FIXME: we need to think about better support for --exact
2236 if (opt->exact)
2237 throwCantPackExact();
2238
2239 const unsigned objs = ih.objects;
2240 readSectionHeaders(objs, sizeof(ih));
2241 if (!opt->force && handleForceOption())
2242 throwCantPack("unexpected value in PE header (try --force)");
2243 checkHeaderValues(ih.subsystem, subsystem_mask, ih.entry, ih.filealign);
2244
2245 //remove certificate directory entry
2246 if (IDSIZE(PEDIR_SEC))
2247 IDSIZE(PEDIR_SEC) = IDADDR(PEDIR_SEC) = 0;
2248
2249 ih.flags |= handleStripRelocs(ih.imagebase, default_imagebase, ih.dllflags);
2250
2251 handleStub(fi,fo,pe_offset);
2252 unsigned overlaystart = readSections(objs, ih.imagesize, ih.filealign, ih.datasize);
2253 unsigned overlay = file_size - stripDebug(overlaystart);
2254 if (overlay >= (unsigned) file_size)
2255 overlay = 0;
2256 checkOverlay(overlay);
2257
2258 Resource res(ibuf, ibuf + ibuf.getSize());
2259 Interval tlsiv(ibuf);
2260 Interval loadconfiv(ibuf);
2261 Export xport((char*)(unsigned char*)ibuf);
2262
2263 const unsigned dllstrings = processImports();
2264 processTls(&tlsiv); // call before processRelocs!!
2265 processLoadConf(&loadconfiv);
2266 processResources(&res);
2267 processExports(&xport);
2268 processRelocs();
2269
2270 //OutputFile::dump("x1", ibuf, usize);
2271
2272 // some checks for broken linkers - disable filter if necessary
2273 bool allow_filter = true;
2274 if (/*FIXME ih.codebase == ih.database
2275 ||*/ ih.codebase + ih.codesize > ih.imagesize
2276 || (isection[virta2objnum(ih.codebase,isection,objs)].flags & PEFL_CODE) == 0)
2277 allow_filter = false;
2278
2279 const unsigned oam1 = ih.objectalign - 1;
2280 if ((1+ oam1) & oam1) { // ih.objectalign is not a power of 2
2281 char buf[32]; snprintf(buf, sizeof(buf), "bad alignment %#x", 1+ oam1);
2282 throwCantPack(buf);
2283 }
2284
2285 // FIXME: disabled: the uncompressor would not allocate enough memory
2286 //objs = tryremove(IDADDR(PEDIR_RELOC),objs);
2287
2288 // FIXME: if the last object has a bss then this won't work
2289 // newvsize = (isection[objs-1].vaddr + isection[objs-1].size + oam1) &~ oam1;
2290 // temporary solution:
2291 unsigned newvsize = (isection[objs-1].vaddr + isection[objs-1].vsize + oam1) &~ oam1;
2292
2293 //fprintf(stderr,"newvsize=%x objs=%d\n",newvsize,objs);
2294 if (newvsize + soimport + sorelocs > ibuf.getSize())
2295 throwInternalError("buffer too small 2");
2296 memcpy(ibuf+newvsize,oimport,soimport);
2297 memcpy(ibuf+newvsize+soimport,orelocs,sorelocs);
2298
2299 cimports = newvsize - rvamin; // rva of preprocessed imports
2300 crelocs = cimports + soimport; // rva of preprocessed fixups
2301
2302 ph.u_len = newvsize + soimport + sorelocs;
2303
2304 // some extra data for uncompression support
2305 unsigned s = 0;
2306 upx_byte * const p1 = ibuf.subref("bad ph.u_len %#x", ph.u_len, sizeof(ih));
2307 memcpy(p1 + s,&ih,sizeof (ih));
2308 s += sizeof (ih);
2309 memcpy(p1 + s,isection,ih.objects * sizeof(*isection));
2310 s += ih.objects * sizeof(*isection);
2311 if (soimport)
2312 {
2313 set_le32(p1 + s,cimports);
2314 set_le32(p1 + s + 4,dllstrings);
2315 s += 8;
2316 }
2317 if (sorelocs)
2318 {
2319 set_le32(p1 + s,crelocs);
2320 p1[s + 4] = (unsigned char) (big_relocs & 6);
2321 s += 5;
2322 }
2323 if (soresources)
2324 {
2325 set_le16(p1 + s,icondir_count);
2326 s += 2;
2327 }
2328 // end of extra data
2329 set_le32(p1 + s,ptr_diff(p1,ibuf) - rvamin);
2330 s += 4;
2331 ph.u_len += s;
2332 obuf.allocForCompression(ph.u_len);
2333
2334 // prepare packheader
2335 if (ph.u_len < rvamin) { // readSectionHeaders() should have caught this
2336 char buf[64]; snprintf(buf, sizeof(buf),
2337 "bad PE header ph.u_len=%#x rvamin=%#x", ph.u_len, rvamin);
2338 throwInternalError(buf);
2339 }
2340 ph.u_len -= rvamin;
2341 // prepare filter
2342 Filter ft(ph.level);
2343 ft.buf_len = ih.codesize;
2344 ft.addvalue = ih.codebase - rvamin;
2345 // compress
2346 int filter_strategy = allow_filter ? 0 : -3;
2347
2348 // disable filters for files with broken headers
2349 if (ih.codebase + ih.codesize > ph.u_len)
2350 {
2351 ft.buf_len = 1;
2352 filter_strategy = -3;
2353 }
2354
2355 callCompressWithFilters(ft, filter_strategy, ih.codebase);
2356 // info: see buildLoader()
2357 newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1;
2358 if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4)
2359 tlsindex = 0;
2360
2361 int identsize = 0;
2362 const unsigned codesize = getLoaderSection("IDENTSTR",&identsize);
2363 assert(identsize > 0);
2364 unsigned ic;
2365 getLoaderSection("UPX1HEAD",(int*)&ic);
2366 identsize += ic;
2367
2368 const unsigned oobjs = last_section_rsrc_only ? 4 : 3;
2369 ////pe_section_t osection[oobjs];
2370 pe_section_t osection[4];
2371 // section 0 : bss
2372 // 1 : [ident + header] + packed_data + unpacker + tls + loadconf
2373 // 2 : not compressed data
2374 // 3 : resource data -- wince 5 needs a new section for this
2375
2376 // the last section should start with the resource data, because lots of lame
2377 // windoze codes assume that resources starts on the beginning of a section
2378
2379 // note: there should be no data in the last section which needs fixup
2380
2381 // identsplit - number of ident + (upx header) bytes to put into the PE header
2382 const unsigned sizeof_osection = sizeof(osection[0]) * oobjs;
2383 int identsplit = pe_offset + sizeof_osection + sizeof(ht);
2384 if ((identsplit & 0x1ff) == 0)
2385 identsplit = 0;
2386 else if (((identsplit + identsize) ^ identsplit) < 0x200)
2387 identsplit = identsize;
2388 else
2389 identsplit = ALIGN_GAP(identsplit, 0x200);
2390 ic = identsize - identsplit;
2391
2392 const unsigned c_len = ((ph.c_len + ic) & 15) == 0 ? ph.c_len : ph.c_len + 16 - ((ph.c_len + ic) & 15);
2393 obuf.clear(ph.c_len, c_len - ph.c_len);
2394
2395 const unsigned s1size = ALIGN_UP(ic + c_len + codesize, (unsigned) sizeof(LEXX)) + sotls + soloadconf;
2396 const unsigned s1addr = (newvsize - (ic + c_len) + oam1) &~ oam1;
2397
2398 const unsigned ncsection = (s1addr + s1size + oam1) &~ oam1;
2399 const unsigned upxsection = s1addr + ic + c_len;
2400
2401 Reloc rel(1024); // new relocations are put here
2402 addNewRelocations(rel, upxsection);
2403
2404 // new PE header
2405 memcpy(&oh,&ih,sizeof(oh));
2406 oh.filealign = 0x200; // identsplit depends on this
2407 memset(osection,0,sizeof(osection));
2408
2409 oh.entry = upxsection;
2410 oh.objects = oobjs;
2411 oh.chksum = 0;
2412
2413 // fill the data directory
2414 ODADDR(PEDIR_DEBUG) = 0;
2415 ODSIZE(PEDIR_DEBUG) = 0;
2416 ODADDR(PEDIR_IAT) = 0;
2417 ODSIZE(PEDIR_IAT) = 0;
2418 ODADDR(PEDIR_BOUNDIM) = 0;
2419 ODSIZE(PEDIR_BOUNDIM) = 0;
2420
2421 // tls & loadconf are put into section 1
2422 ic = s1addr + s1size - sotls - soloadconf;
2423
2424 if (use_tls_callbacks)
2425 tls_handler_offset = linker->getSymbolOffset("PETLSC2") + upxsection;
2426
2427 processTls(&rel,&tlsiv,ic);
2428 ODADDR(PEDIR_TLS) = sotls ? ic : 0;
2429 ODSIZE(PEDIR_TLS) = sotls ? (sizeof(LEXX) == 4 ? 0x18 : 0x28) : 0;
2430 ic += sotls;
2431
2432 processLoadConf(&rel, &loadconfiv, ic);
2433 ODADDR(PEDIR_LOADCONF) = soloadconf ? ic : 0;
2434 ODSIZE(PEDIR_LOADCONF) = soloadconf;
2435 ic += soloadconf;
2436
2437 const bool rel_at_sections_start = oobjs == 4;
2438
2439 ic = ncsection;
2440 if (!last_section_rsrc_only)
2441 callProcessResources(res, ic);
2442 if (rel_at_sections_start)
2443 callProcessRelocs(rel, ic);
2444
2445 processImports2(ic, getProcessImportParam(upxsection));
2446 ODADDR(PEDIR_IMPORT) = ic;
2447 ODSIZE(PEDIR_IMPORT) = soimpdlls;
2448 ic += soimpdlls;
2449
2450 processExports(&xport,ic);
2451 ODADDR(PEDIR_EXPORT) = soexport ? ic : 0;
2452 ODSIZE(PEDIR_EXPORT) = soexport;
2453 if (!isdll && opt->win32_pe.compress_exports)
2454 {
2455 ODADDR(PEDIR_EXPORT) = IDADDR(PEDIR_EXPORT);
2456 ODSIZE(PEDIR_EXPORT) = IDSIZE(PEDIR_EXPORT);
2457 }
2458 ic += soexport;
2459
2460 if (!rel_at_sections_start)
2461 callProcessRelocs(rel, ic);
2462
2463 // when the resource is put alone into section 3
2464 const unsigned res_start = (ic + oam1) &~ oam1;;
2465 if (last_section_rsrc_only)
2466 callProcessResources(res, ic = res_start);
2467
2468 defineSymbols(ncsection, upxsection, sizeof(oh),
2469 identsize - identsplit, s1addr);
2470 defineFilterSymbols(&ft);
2471 relocateLoader();
2472 const unsigned lsize = getLoaderSize();
2473 MemBuffer loader(lsize);
2474 memcpy(loader,getLoader(),lsize);
2475 patchPackHeader(loader, lsize);
2476
2477 const unsigned ncsize = soxrelocs + soimpdlls + soexport
2478 + (!last_section_rsrc_only ? soresources : 0);
2479 const unsigned fam1 = oh.filealign - 1;
2480
2481 // this one is tricky: it seems windoze touches 4 bytes after
2482 // the end of the relocation data - so we have to increase
2483 // the virtual size of this section
2484 const unsigned ncsize_virt_increase = (ncsize & oam1) == 0 ? 8 : 0;
2485
2486 // fill the sections
2487 strcpy(osection[0].name,"UPX0");
2488 strcpy(osection[1].name,"UPX1");
2489 // after some windoze debugging I found that the name of the sections
2490 // DOES matter :( .rsrc is used by oleaut32.dll (TYPELIBS)
2491 // and because of this lame dll, the resource stuff must be the
2492 // first in the 3rd section - the author of this dll seems to be
2493 // too idiot to use the data directories... M$ suxx 4 ever!
2494 // ... even worse: exploder.exe in NiceTry also depends on this to
2495 // locate version info
2496
2497 strcpy(osection[2].name, !last_section_rsrc_only && soresources ? ".rsrc" : "UPX2");
2498
2499 osection[0].vaddr = rvamin;
2500 osection[1].vaddr = s1addr;
2501 osection[2].vaddr = ncsection;
2502
2503 osection[0].size = 0;
2504 osection[1].size = (s1size + fam1) &~ fam1;
2505 osection[2].size = (ncsize + fam1) &~ fam1;
2506
2507 osection[0].vsize = osection[1].vaddr - osection[0].vaddr;
2508 if (oobjs == 3)
2509 {
2510 osection[1].vsize = (osection[1].size + oam1) &~ oam1;
2511 osection[2].vsize = (osection[2].size + ncsize_virt_increase + oam1) &~ oam1;
2512 oh.imagesize = osection[2].vaddr + osection[2].vsize;
2513 osection[0].rawdataptr = (pe_offset + sizeof(ht) + sizeof_osection + fam1) &~ (size_t)fam1;
2514 osection[1].rawdataptr = osection[0].rawdataptr;
2515 }
2516 else
2517 {
2518 osection[1].vsize = osection[1].size;
2519 osection[2].vsize = osection[2].size;
2520 osection[0].rawdataptr = 0;
2521 osection[1].rawdataptr = (pe_offset + sizeof(ht) + sizeof_osection + fam1) &~ (size_t)fam1;
2522 }
2523 osection[2].rawdataptr = osection[1].rawdataptr + osection[1].size;
2524
2525 osection[0].flags = (unsigned) (PEFL_BSS|PEFL_EXEC|PEFL_WRITE|PEFL_READ);
2526 osection[1].flags = (unsigned) (PEFL_DATA|PEFL_EXEC|PEFL_WRITE|PEFL_READ);
2527 osection[2].flags = (unsigned) (PEFL_DATA|PEFL_WRITE|PEFL_READ);
2528
2529 if (oobjs == 4)
2530 {
2531 strcpy(osection[3].name, ".rsrc");
2532 osection[3].vaddr = res_start;
2533 osection[3].size = (soresources + fam1) &~ fam1;
2534 osection[3].vsize = osection[3].size;
2535 osection[3].rawdataptr = osection[2].rawdataptr + osection[2].size;
2536 osection[2].flags = (unsigned) (PEFL_DATA|PEFL_READ);
2537 osection[3].flags = (unsigned) (PEFL_DATA|PEFL_READ);
2538 oh.imagesize = (osection[3].vaddr + osection[3].vsize + oam1) &~ oam1;
2539 if (soresources == 0)
2540 {
2541 oh.objects = 3;
2542 memset(&osection[3], 0, sizeof(osection[3]));
2543 }
2544 }
2545
2546 oh.bsssize = osection[0].vsize;
2547 oh.datasize = osection[2].vsize + (oobjs > 3 ? osection[3].vsize : 0);
2548 setOhDataBase(osection);
2549 oh.codesize = osection[1].vsize;
2550 oh.codebase = osection[1].vaddr;
2551 setOhHeaderSize(osection);
2552 if (rvamin < osection[0].rawdataptr)
2553 throwCantPack("object alignment too small");
2554
2555 if (opt->win32_pe.strip_relocs && !isdll)
2556 oh.flags |= RELOCS_STRIPPED;
2557
2558 //for (ic = 0; ic < oh.filealign; ic += 4)
2559 // set_le32(ibuf + ic,get_le32("UPX "));
2560 ibuf.clear(0, oh.filealign);
2561
2562 info("Image size change: %u -> %u KiB",
2563 ih.imagesize / 1024, oh.imagesize / 1024);
2564
2565 infoHeader("[Writing compressed file]");
2566
2567 // write loader + compressed file
2568 fo->write(&oh,sizeof(oh));
2569 fo->write(osection,sizeof(osection[0])*oobjs);
2570 // some alignment
2571 if (identsplit == identsize)
2572 {
2573 unsigned n = osection[oobjs == 3 ? 0 : 1].rawdataptr - fo->getBytesWritten() - identsize;
2574 assert(n <= oh.filealign);
2575 fo->write(ibuf, n);
2576 }
2577 fo->write(loader + codesize,identsize);
2578 infoWriting("loader", fo->getBytesWritten());
2579 fo->write(obuf,c_len);
2580 infoWriting("compressed data", c_len);
2581 fo->write(loader,codesize);
2582 if (opt->debug.dump_stub_loader)
2583 OutputFile::dump(opt->debug.dump_stub_loader, loader, codesize);
2584 if ((ic = fo->getBytesWritten() & (sizeof(LEXX) - 1)) != 0)
2585 fo->write(ibuf, sizeof(LEXX) - ic);
2586 fo->write(otls,sotls);
2587 fo->write(oloadconf, soloadconf);
2588 if ((ic = fo->getBytesWritten() & fam1) != 0)
2589 fo->write(ibuf,oh.filealign - ic);
2590 if (!last_section_rsrc_only)
2591 fo->write(oresources,soresources);
2592 else
2593 fo->write(oxrelocs,soxrelocs);
2594 fo->write(oimpdlls,soimpdlls);
2595 fo->write(oexport,soexport);
2596 fo->write(oxrelocs,soxrelocs);
2597 if (!last_section_rsrc_only)
2598 fo->write(oxrelocs,soxrelocs);
2599
2600 if ((ic = fo->getBytesWritten() & fam1) != 0)
2601 fo->write(ibuf,oh.filealign - ic);
2602
2603 if (last_section_rsrc_only)
2604 {
2605 fo->write(oresources,soresources);
2606 if ((ic = fo->getBytesWritten() & fam1) != 0)
2607 fo->write(ibuf,oh.filealign - ic);
2608 }
2609
2610 #if 0
2611 printf("%-13s: program hdr : %8ld bytes\n", getName(), (long) sizeof(oh));
2612 printf("%-13s: sections : %8ld bytes\n", getName(), (long) sizeof(osection[0])*oobjs);
2613 printf("%-13s: ident : %8ld bytes\n", getName(), (long) identsize);
2614 printf("%-13s: compressed : %8ld bytes\n", getName(), (long) c_len);
2615 printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) codesize);
2616 printf("%-13s: tls : %8ld bytes\n", getName(), (long) sotls);
2617 printf("%-13s: resources : %8ld bytes\n", getName(), (long) soresources);
2618 printf("%-13s: imports : %8ld bytes\n", getName(), (long) soimpdlls);
2619 printf("%-13s: exports : %8ld bytes\n", getName(), (long) soexport);
2620 printf("%-13s: relocs : %8ld bytes\n", getName(), (long) soxrelocs);
2621 printf("%-13s: loadconf : %8ld bytes\n", getName(), (long) soloadconf);
2622 #endif
2623
2624 // verify
2625 verifyOverlappingDecompression();
2626
2627 // copy the overlay
2628 copyOverlay(fo, overlay, &obuf);
2629
2630 // finally check the compression ratio
2631 if (!checkFinalCompressionRatio(fo))
2632 throwNotCompressible();
2633 }
2634
2635 /*************************************************************************
2636 // unpack
2637 **************************************************************************/
2638
rebuildRelocs(upx_byte * & extrainfo,unsigned bits,unsigned flags,upx_uint64_t imagebase)2639 void PeFile::rebuildRelocs(upx_byte *& extrainfo, unsigned bits,
2640 unsigned flags, upx_uint64_t imagebase)
2641 {
2642 assert(bits == 32 || bits == 64);
2643 if (!ODADDR(PEDIR_RELOC) || !ODSIZE(PEDIR_RELOC) || (flags & RELOCS_STRIPPED))
2644 return;
2645
2646 if (ODSIZE(PEDIR_RELOC) == 8) // some tricky dlls use this
2647 {
2648 omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin, "\x0\x0\x0\x0\x8\x0\x0\x0", 8);
2649 return;
2650 }
2651
2652 upx_byte *rdata = obuf + get_le32(extrainfo);
2653 const upx_byte big = extrainfo[4];
2654 extrainfo += 5;
2655
2656 // upx_byte *p = rdata;
2657 OPTR_I(upx_byte, p, rdata);
2658 MemBuffer wrkmem;
2659 unsigned relocn = unoptimizeReloc(&rdata,obuf,&wrkmem,1,bits);
2660 unsigned r16 = 0;
2661 if (big & 6) // 16 bit relocations
2662 {
2663 const LE32 *q = (LE32*) rdata;
2664 while (*q++)
2665 r16++;
2666 if ((big & 6) == 6)
2667 while (*++q)
2668 r16++;
2669 }
2670 Reloc rel(relocn + r16);
2671
2672 if (big & 6)
2673 {
2674 LE32 *q = (LE32*) rdata;
2675 while (*q)
2676 rel.add(*q++ + rvamin,(big & 4) ? 2 : 1);
2677 if ((big & 6) == 6)
2678 while (*++q)
2679 rel.add(*q + rvamin,1);
2680 rdata = (upx_byte*) q;
2681 }
2682
2683 //memset(p,0,rdata - p);
2684
2685 for (unsigned ic = 0; ic < relocn; ic++)
2686 {
2687 p = obuf + get_le32(wrkmem + 4 * ic);
2688 if (bits == 32)
2689 set_le32(p, get_le32((unsigned char *)p) + imagebase + rvamin);
2690 else
2691 set_le64(p, get_le64((unsigned char *)p) + imagebase + rvamin);
2692 rel.add(rvamin + get_le32(wrkmem + 4 * ic), bits == 32 ? 3 : 10);
2693 }
2694 rel.finish (oxrelocs,soxrelocs);
2695
2696 if (opt->win32_pe.strip_relocs && !isdll)
2697 {
2698 obuf.clear(ODADDR(PEDIR_RELOC) - rvamin, ODSIZE(PEDIR_RELOC));
2699 ODADDR(PEDIR_RELOC) = 0;
2700 soxrelocs = 0;
2701 // FIXME: try to remove the original relocation section somehow
2702 }
2703 else
2704 omemcpy(obuf + ODADDR(PEDIR_RELOC) - rvamin,oxrelocs,soxrelocs);
2705 delete [] oxrelocs; oxrelocs = NULL;
2706 wrkmem.dealloc();
2707
2708 ODSIZE(PEDIR_RELOC) = soxrelocs;
2709 }
2710
rebuildExports()2711 void PeFile::rebuildExports()
2712 {
2713 if (ODSIZE(PEDIR_EXPORT) == 0 || ODADDR(PEDIR_EXPORT) == IDADDR(PEDIR_EXPORT))
2714 return; // nothing to do
2715
2716 opt->win32_pe.compress_exports = 0;
2717 Export xport((char*)(unsigned char*) ibuf - isection[2].vaddr);
2718 processExports(&xport);
2719 processExports(&xport,ODADDR(PEDIR_EXPORT));
2720 omemcpy(obuf + ODADDR(PEDIR_EXPORT) - rvamin,oexport,soexport);
2721 }
2722
rebuildTls()2723 void PeFile::rebuildTls()
2724 {
2725 // this is an easy one : just do nothing ;-)
2726 }
2727
rebuildResources(upx_byte * & extrainfo,unsigned lastvaddr)2728 void PeFile::rebuildResources(upx_byte *& extrainfo, unsigned lastvaddr)
2729 {
2730 if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
2731 return;
2732
2733 icondir_count = get_le16(extrainfo);
2734 extrainfo += 2;
2735
2736 const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
2737
2738 if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize())
2739 throwCantUnpack("corrupted PE header");
2740
2741 const upx_byte *r = ibuf - lastvaddr;
2742 Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize());
2743 while (res.next())
2744 if (res.offs() > vaddr)
2745 {
2746 ICHECK(r + res.offs() - 4, 4);
2747 unsigned origoffs = get_le32(r + res.offs() - 4);
2748 res.newoffs() = origoffs;
2749 omemcpy(obuf + origoffs - rvamin,r + res.offs(),res.size());
2750 if (icondir_count && res.itype() == RT_GROUP_ICON)
2751 {
2752 set_le16(obuf + origoffs - rvamin + 4,icondir_count);
2753 icondir_count = 0;
2754 }
2755 }
2756 upx_byte *p = res.build();
2757 OCHECK(obuf + ODADDR(PEDIR_RESOURCE) - rvamin, 16);
2758 // write back when the original is zeroed
2759 if (get_le32(obuf + ODADDR(PEDIR_RESOURCE) - rvamin + 12) == 0)
2760 omemcpy(obuf + ODADDR(PEDIR_RESOURCE) - rvamin, p, res.dirsize());
2761 delete [] p;
2762 }
2763
2764 template <typename LEXX, typename ord_mask_t>
rebuildImports(upx_byte * & extrainfo,ord_mask_t ord_mask,bool set_oft)2765 void PeFile::rebuildImports(upx_byte *& extrainfo,
2766 ord_mask_t ord_mask, bool set_oft)
2767 {
2768 if (ODADDR(PEDIR_IMPORT) == 0
2769 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc))
2770 return;
2771
2772 // const upx_byte * const idata = obuf + get_le32(extrainfo);
2773 OPTR_C(const upx_byte, idata, obuf + get_le32(extrainfo));
2774 const unsigned inamespos = get_le32(extrainfo + 4);
2775 extrainfo += 8;
2776
2777 unsigned sdllnames = 0;
2778
2779 // const upx_byte *import = ibuf + IDADDR(PEDIR_IMPORT) - isection[2].vaddr;
2780 // const upx_byte *p;
2781 IPTR_I_D(const upx_byte, import, IDADDR(PEDIR_IMPORT) - isection[2].vaddr);
2782 OPTR(const upx_byte, p);
2783
2784 for (p = idata; get_le32(p) != 0; ++p)
2785 {
2786 const upx_byte *dname = get_le32(p) + import;
2787 ICHECK(dname, 1);
2788 const unsigned dlen = strlen(dname);
2789 ICHECK(dname, dlen + 1);
2790
2791 sdllnames += dlen + 1;
2792 for (p += 8; *p;)
2793 if (*p == 1)
2794 p += strlen(++p) + 1;
2795 else if (*p == 0xff)
2796 p += 3; // ordinal
2797 else
2798 p += 5;
2799 }
2800 sdllnames = ALIGN_UP(sdllnames, 2u);
2801
2802 upx_byte * const Obuf = obuf - rvamin;
2803 import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
2804 import_desc *im = im0;
2805 upx_byte *dllnames = Obuf + inamespos;
2806 upx_byte *importednames = dllnames + sdllnames;
2807 upx_byte * const importednames_start = importednames;
2808
2809 for (p = idata; get_le32(p) != 0; ++p)
2810 {
2811 // restore the name of the dll
2812 const upx_byte *dname = get_le32(p) + import;
2813 ICHECK(dname, 1);
2814 const unsigned dlen = strlen(dname);
2815 ICHECK(dname, dlen + 1);
2816
2817 const unsigned iatoffs = get_le32(p + 4) + rvamin;
2818 if (inamespos)
2819 {
2820 // now I rebuild the dll names
2821 OCHECK(dllnames, dlen + 1);
2822 strcpy(dllnames, dname);
2823 im->dllname = ptr_diff(dllnames,Obuf);
2824 //;;;printf("\ndll: %s:",dllnames);
2825 dllnames += dlen + 1;
2826 }
2827 else
2828 {
2829 OCHECK(Obuf + im->dllname, dlen + 1);
2830 strcpy(Obuf + im->dllname, dname);
2831 }
2832 im->iat = iatoffs;
2833 if (set_oft)
2834 im->oft = iatoffs;
2835
2836 OPTR_I(LEXX, newiat, (LEXX *) (Obuf + iatoffs));
2837
2838 // restore the imported names+ordinals
2839 for (p += 8; *p; ++newiat)
2840 if (*p == 1)
2841 {
2842 const unsigned ilen = strlen(++p) + 1;
2843 if (inamespos)
2844 {
2845 if (ptr_diff(importednames, importednames_start) & 1)
2846 importednames -= 1;
2847 omemcpy(importednames + 2, p, ilen);
2848 //;;;printf(" %s",importednames+2);
2849 *newiat = ptr_diff(importednames, Obuf);
2850 importednames += 2 + ilen;
2851 }
2852 else
2853 {
2854 OCHECK(Obuf + (*newiat + 2), ilen + 1);
2855 strcpy(Obuf + (*newiat + 2), p);
2856 }
2857 p += ilen;
2858 }
2859 else if (*p == 0xff)
2860 {
2861 *newiat = get_le16(p + 1) + ord_mask;
2862 //;;;printf(" %x",(unsigned)*newiat);
2863 p += 3;
2864 }
2865 else
2866 {
2867 *newiat = *(const LEXX*)(get_le32(p + 1) + import);
2868 assert(*newiat & ord_mask);
2869 p += 5;
2870 }
2871 *newiat = 0;
2872 im++;
2873 }
2874 //memset(idata,0,p - idata);
2875 }
2876
2877 template <typename ht, typename LEXX, typename ord_mask_t>
unpack0(OutputFile * fo,const ht & ih,ht & oh,ord_mask_t ord_mask,bool set_oft)2878 void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh,
2879 ord_mask_t ord_mask, bool set_oft)
2880 {
2881 //infoHeader("[Processing %s, format %s, %d sections]", fn_basename(fi->getName()), getName(), objs);
2882
2883 handleStub(fi,fo,pe_offset);
2884 if (ih.filealign == 0)
2885 throwCantUnpack("unexpected value in the PE header");
2886
2887 const unsigned iobjs = ih.objects;
2888 const unsigned overlay = file_size - ALIGN_UP(isection[iobjs - 1].rawdataptr
2889 + isection[iobjs - 1].size,
2890 ih.filealign);
2891 checkOverlay(overlay);
2892
2893 ibuf.alloc(ph.c_len);
2894 obuf.allocForUncompression(ph.u_len);
2895 fi->seek(isection[1].rawdataptr - 64 + ph.buf_offset + ph.getPackHeaderSize(),SEEK_SET);
2896 fi->readx(ibuf,ph.c_len);
2897
2898 // decompress
2899 decompress(ibuf,obuf);
2900 unsigned skip = get_le32(obuf + ph.u_len - 4);
2901 unsigned take = sizeof(oh);
2902 upx_byte *extrainfo = obuf.subref("bad extrainfo offset %#x", skip, take);
2903 //upx_byte * const eistart = extrainfo;
2904
2905 memcpy(&oh, extrainfo, take);
2906 extrainfo += take;
2907 skip += take;
2908 unsigned objs = oh.objects;
2909
2910 if ((int) objs <= 0 || isection[2].size == 0)
2911 throwCantUnpack("unexpected value in the PE header");
2912 Array(pe_section_t, osection, objs);
2913 take = sizeof(pe_section_t) * objs;
2914 extrainfo = obuf.subref("bad extra section size at %#x", skip, take);
2915 memcpy(osection, extrainfo, take);
2916 extrainfo += take;
2917 skip += take;
2918 rvamin = osection[0].vaddr;
2919
2920 // read the noncompressed section
2921 ibuf.dealloc();
2922 ibuf.alloc(isection[2].size);
2923 fi->seek(isection[2].rawdataptr,SEEK_SET);
2924 fi->readx(ibuf,isection[2].size);
2925
2926 // unfilter
2927 if (ph.filter)
2928 {
2929 Filter ft(ph.level);
2930 ft.init(ph.filter,oh.codebase - rvamin);
2931 ft.cto = (unsigned char) ph.filter_cto;
2932 OCHECK(obuf + oh.codebase - rvamin, oh.codesize);
2933 ft.unfilter(obuf + oh.codebase - rvamin, oh.codesize);
2934 }
2935
2936 rebuildImports<LEXX>(extrainfo, ord_mask, set_oft);
2937 rebuildRelocs(extrainfo, sizeof(ih.imagebase) * 8, oh.flags, oh.imagebase);
2938 rebuildTls();
2939 rebuildExports();
2940
2941 if (iobjs == 4)
2942 {
2943 // read the resource section if present
2944 ibuf.dealloc();
2945 ibuf.alloc(isection[3].size);
2946 fi->seek(isection[3].rawdataptr,SEEK_SET);
2947 fi->readx(ibuf,isection[3].size);
2948 }
2949
2950 rebuildResources(extrainfo, isection[ih.objects - 1].vaddr);
2951
2952 //FIXME: this does bad things if the relocation section got removed
2953 // during compression ...
2954 //memset(eistart,0,extrainfo - eistart + 4);
2955
2956 // fill the data directory
2957 ODADDR(PEDIR_DEBUG) = 0;
2958 ODSIZE(PEDIR_DEBUG) = 0;
2959 ODADDR(PEDIR_IAT) = 0;
2960 ODSIZE(PEDIR_IAT) = 0;
2961 ODADDR(PEDIR_BOUNDIM) = 0;
2962 ODSIZE(PEDIR_BOUNDIM) = 0;
2963
2964 // oh.headersize = osection[0].rawdataptr;
2965 // oh.headersize = ALIGN_UP(pe_offset + sizeof(oh) + sizeof(pe_section_t) * objs, oh.filealign);
2966 oh.headersize = rvamin;
2967 oh.chksum = 0;
2968
2969 //NEW: disable reloc stripping if ASLR is enabled
2970 if(ih.dllflags & IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE)
2971 opt->win32_pe.strip_relocs = false;
2972
2973 // FIXME: ih.flags is checked here because of a bug in UPX 0.92
2974 if ((opt->win32_pe.strip_relocs && !isdll) || (ih.flags & RELOCS_STRIPPED))
2975 {
2976 oh.flags |= RELOCS_STRIPPED;
2977 ODADDR(PEDIR_RELOC) = 0;
2978 ODSIZE(PEDIR_RELOC) = 0;
2979 }
2980
2981 // write decompressed file
2982 if (fo)
2983 {
2984 unsigned ic;
2985 for (ic = 0; ic < objs && osection[ic].rawdataptr == 0; ic++)
2986 ;
2987
2988 ibuf.dealloc();
2989 ibuf.alloc(osection[ic].rawdataptr);
2990 ibuf.clear();
2991 infoHeader("[Writing uncompressed file]");
2992
2993 // write loader + compressed file
2994 fo->write(&oh,sizeof(oh));
2995 fo->write(osection,objs * sizeof(pe_section_t));
2996 fo->write(ibuf,osection[ic].rawdataptr - fo->getBytesWritten());
2997 for (ic = 0; ic < objs; ic++)
2998 if (osection[ic].rawdataptr)
2999 fo->write(obuf + osection[ic].vaddr - rvamin,ALIGN_UP(osection[ic].size,oh.filealign));
3000 copyOverlay(fo, overlay, &obuf);
3001 }
3002 ibuf.dealloc();
3003 }
3004
canUnpack0(unsigned max_sections,LE16 & ih_objects,LE32 & ih_entry,unsigned ihsize)3005 int PeFile::canUnpack0(unsigned max_sections, LE16 &ih_objects,
3006 LE32 &ih_entry, unsigned ihsize)
3007 {
3008 if (!canPack())
3009 return false;
3010
3011 unsigned objs = ih_objects;
3012 isection = New(pe_section_t, objs);
3013 fi->seek(pe_offset + ihsize, SEEK_SET);
3014 fi->readx(isection,sizeof(pe_section_t)*objs);
3015 if (ih_objects < 3)
3016 return -1;
3017 bool is_packed = ((ih_objects == 3 || ih_objects == max_sections) &&
3018 (IDSIZE(15) || ih_entry > isection[1].vaddr));
3019 bool found_ph = false;
3020 if (memcmp(isection[0].name,"UPX",3) == 0)
3021 {
3022 // current version
3023 fi->seek(isection[1].rawdataptr - 64, SEEK_SET);
3024 found_ph = readPackHeader(1024);
3025 if (!found_ph)
3026 {
3027 // old versions
3028 fi->seek(isection[2].rawdataptr, SEEK_SET);
3029 found_ph = readPackHeader(1024);
3030 }
3031 }
3032 if (is_packed && found_ph)
3033 return true;
3034 if (!is_packed && !found_ph)
3035 return -1;
3036 if (is_packed && ih_entry < isection[2].vaddr)
3037 {
3038 unsigned char buf[256];
3039 bool x = false;
3040
3041 memset(buf, 0, sizeof(buf));
3042 try {
3043 fi->seek(ih_entry - isection[1].vaddr + isection[1].rawdataptr, SEEK_SET);
3044 fi->read(buf, sizeof(buf));
3045
3046 // FIXME this is for x86
3047 static const unsigned char magic[] = "\x8b\x1e\x83\xee\xfc\x11\xdb";
3048 // mov ebx, [esi]; sub esi, -4; adc ebx,ebx
3049
3050 int offset = find(buf, sizeof(buf), magic, 7);
3051 if (offset >= 0 && find(buf + offset + 1, sizeof(buf) - offset - 1, magic, 7) >= 0)
3052 x = true;
3053 } catch (...) {
3054 //x = true;
3055 }
3056 if (x)
3057 throwCantUnpack("file is modified/hacked/protected; take care!!!");
3058 else
3059 throwCantUnpack("file is possibly modified/hacked/protected; take care!");
3060 return false; // not reached
3061 }
3062
3063 // FIXME: what should we say here ?
3064 //throwCantUnpack("file is possibly modified/hacked/protected; take care!");
3065 return false;
3066 }
3067
ilinkerGetAddress(const char * d,const char * n) const3068 upx_uint64_t PeFile::ilinkerGetAddress(const char *d, const char *n) const
3069 {
3070 return ilinker->getAddress(d, n);
3071 }
3072
~PeFile()3073 PeFile::~PeFile()
3074 {
3075 delete [] isection;
3076 delete [] orelocs;
3077 delete [] oimport;
3078 oimpdlls = NULL;
3079 delete [] oexport;
3080 delete [] otls;
3081 delete [] oresources;
3082 delete [] oxrelocs;
3083 delete [] oloadconf;
3084 delete ilinker;
3085 //delete res;
3086 }
3087
3088
3089 /*************************************************************************
3090 // PeFile32
3091 **************************************************************************/
3092
PeFile32(InputFile * f)3093 PeFile32::PeFile32(InputFile *f) : super(f)
3094 {
3095 COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 248)
3096 COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t)
3097
3098 iddirs = ih.ddirs;
3099 oddirs = oh.ddirs;
3100 }
3101
~PeFile32()3102 PeFile32::~PeFile32()
3103 {}
3104
readPeHeader()3105 void PeFile32::readPeHeader()
3106 {
3107 fi->readx(&ih,sizeof(ih));
3108 isdll = ((ih.flags & DLL_FLAG) != 0);
3109 }
3110
pack0(OutputFile * fo,unsigned subsystem_mask,upx_uint64_t default_imagebase,bool last_section_rsrc_only)3111 void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask,
3112 upx_uint64_t default_imagebase,
3113 bool last_section_rsrc_only)
3114 {
3115 super::pack0<LE32>(fo, ih, oh, subsystem_mask,
3116 default_imagebase, last_section_rsrc_only);
3117 }
3118
unpack(OutputFile * fo)3119 void PeFile32::unpack(OutputFile *fo)
3120 {
3121 bool set_oft = getFormat() == UPX_F_WINCE_ARM_PE;
3122 unpack0<pe_header_t, LE32>(fo, ih, oh, 1U << 31, set_oft);
3123 }
3124
canUnpack()3125 int PeFile32::canUnpack()
3126 {
3127 return canUnpack0(getFormat() == UPX_F_WINCE_ARM_PE ? 4 : 3,
3128 ih.objects, ih.entry, sizeof(ih));
3129 }
3130
processImports()3131 unsigned PeFile32::processImports() // pass 1
3132 {
3133 return processImports0<LE32>(1u << 31);
3134 }
3135
processTls(Interval * iv)3136 void PeFile32::processTls(Interval *iv)
3137 {
3138 processTls1<LE32>(iv, ih.imagebase, ih.imagesize);
3139 }
3140
processTls(Reloc * r,const Interval * iv,unsigned a)3141 void PeFile32::processTls(Reloc *r, const Interval *iv, unsigned a)
3142 {
3143 processTls2<LE32>(r, iv, a, ih.imagebase);
3144 }
3145
3146 /*************************************************************************
3147 // PeFile64
3148 **************************************************************************/
3149
PeFile64(InputFile * f)3150 PeFile64::PeFile64(InputFile *f) : super(f)
3151 {
3152 COMPILE_TIME_ASSERT(sizeof(pe_header_t) == 264)
3153 COMPILE_TIME_ASSERT_ALIGNED1(pe_header_t)
3154
3155 iddirs = ih.ddirs;
3156 oddirs = oh.ddirs;
3157 }
3158
~PeFile64()3159 PeFile64::~PeFile64()
3160 {}
3161
readPeHeader()3162 void PeFile64::readPeHeader()
3163 {
3164 fi->readx(&ih,sizeof(ih));
3165 isdll = ((ih.flags & DLL_FLAG) != 0);
3166 }
3167
pack0(OutputFile * fo,unsigned subsystem_mask,upx_uint64_t default_imagebase)3168 void PeFile64::pack0(OutputFile *fo, unsigned subsystem_mask,
3169 upx_uint64_t default_imagebase)
3170 {
3171 super::pack0<LE64>(fo, ih, oh, subsystem_mask, default_imagebase, false);
3172 }
3173
unpack(OutputFile * fo)3174 void PeFile64::unpack(OutputFile *fo)
3175 {
3176 unpack0<pe_header_t, LE64>(fo, ih, oh, 1ULL << 63, false);
3177 }
3178
canUnpack()3179 int PeFile64::canUnpack()
3180 {
3181 return canUnpack0(3, ih.objects, ih.entry, sizeof(ih));
3182 }
3183
processImports()3184 unsigned PeFile64::processImports() // pass 1
3185 {
3186 return processImports0<LE64>(1ULL << 63);
3187 }
3188
processTls(Interval * iv)3189 void PeFile64::processTls(Interval *iv)
3190 {
3191 processTls1<LE64>(iv, ih.imagebase, ih.imagesize);
3192 }
3193
processTls(Reloc * r,const Interval * iv,unsigned a)3194 void PeFile64::processTls(Reloc *r, const Interval *iv, unsigned a)
3195 {
3196 processTls2<LE64>(r, iv, a, ih.imagebase);
3197 }
3198
3199 /*
3200 extra info added to help uncompression:
3201
3202 <ih sizeof(pe_head)>
3203 <pe_section_t objs*sizeof(pe_section_t)>
3204 <start of compressed imports 4> - optional \
3205 <start of the names from uncompressed imports> - opt /
3206 <start of compressed relocs 4> - optional \
3207 <relocation type indicator 1> - optional /
3208 <icondir_count 2> - optional
3209 <offset of extra info 4>
3210 */
3211
3212
3213 /* vim:set ts=4 sw=4 et: */
3214