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