1 /* p_wcle.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 "lefile.h"
34 #include "p_wcle.h"
35 #include "linker.h"
36 
37 static const
38 #include "stub/i386-dos32.watcom.le.h"
39 
40 #define LEOF_READ       (1<<0)
41 #define LEOF_WRITE      (1<<1)
42 #define LEOF_EXEC       (1<<2)
43 #define LEOF_PRELOAD    (1<<6)
44 #define LEOF_HUGE32     (1<<13)
45 
46 #define IOT(x,y)        iobject_table[x].y
47 #define OOT(x,y)        oobject_table[x].y
48 
49 #define LE_STUB_EDI     (1)
50 
51 #ifdef TESTING
52 # define dputc(x,y)     do { if (opt->debug.debug_level) putc(x,y); } while (0)
53 # define Opt_debug      opt->debug.debug_level
54 #else
55 # define dputc(x,y)     ((void)0)
56 # define Opt_debug      0
57 #endif
58 
59 #define my_base_address reserved
60 #define objects         ih.object_table_entries
61 #define pages           ih.memory_pages
62 #define mps             ih.memory_page_size
63 #define opages          oh.memory_pages
64 
65 
66 /*************************************************************************
67 //
68 **************************************************************************/
69 
getCompressionMethods(int method,int level) const70 const int *PackWcle::getCompressionMethods(int method, int level) const
71 {
72     return Packer::getDefaultCompressionMethods_le32(method, level);
73 }
74 
75 
getFilters() const76 const int *PackWcle::getFilters() const
77 {
78     static const int filters[] = {
79         0x26, 0x24, 0x49, 0x46, 0x16, 0x13, 0x14, 0x11,
80         FT_ULTRA_BRUTE, 0x25, 0x15, 0x12,
81     FT_END };
82     return filters;
83 }
84 
85 
newLinker() const86 Linker* PackWcle::newLinker() const
87 {
88     return new ElfLinkerX86;
89 }
90 
91 
buildLoader(const Filter * ft)92 void PackWcle::buildLoader(const Filter *ft)
93 {
94     // prepare loader
95     initLoader(stub_i386_dos32_watcom_le, sizeof(stub_i386_dos32_watcom_le));
96     addLoader("IDENTSTR,WCLEMAIN",
97               ph.first_offset_found == 1 ? "WCLEMAIN02" : "",
98               "WCLEMAIN03,UPX1HEAD,WCLECUTP", NULL);
99 
100     // fake alignment for the start of the decompressor
101     linker->defineSymbol("WCLECUTP", 0x1000);
102 
103     addLoader(getDecompressorSections(), "WCLEMAI2", NULL);
104     if (ft->id)
105     {
106         assert(ft->calls > 0);
107         addLoader(ft->addvalue ? "WCCTTPOS" : "WCCTTNUL", NULL);
108         addFilter32(ft->id);
109     }
110 #if 1
111     // FIXME: if (has_relocation)
112     {
113         addLoader("WCRELOC1,RELOC320",
114                   big_relocs ? "REL32BIG" : "",
115                   "RELOC32J",
116                   NULL
117                  );
118     }
119 #endif
120     addLoader(has_extra_code ? "WCRELSEL" : "",
121               "WCLEMAI4",
122               NULL
123              );
124 }
125 
126 
127 /*************************************************************************
128 // util
129 **************************************************************************/
130 
handleStub(OutputFile * fo)131 void PackWcle::handleStub(OutputFile *fo)
132 {
133     if (fo && !opt->watcom_le.le)
134         Packer::handleStub(fi,fo,le_offset);
135 }
136 
137 
canPack()138 bool PackWcle::canPack()
139 {
140     if (!LeFile::readFileHeader())
141         return false;
142     return true;
143 }
144 
145 
146 /*************************************************************************
147 //
148 **************************************************************************/
149 
150 // IDEA: as all the entries go into object #1, I could create bundles with 255
151 // elements (of course I still have to handle empty bundles)
152 
encodeEntryTable()153 void PackWcle::encodeEntryTable()
154 {
155     unsigned count,object,n;
156     upx_byte *p = ientries;
157     n = 0;
158     while (*p)
159     {
160         count = *p;
161         n += count;
162         if (p[1] == 0) // unused bundle
163             p += 2;
164         else if (p[1] == 3) // 32-bit bundle
165         {
166             object = get_le16(p+2)-1;
167             set_le16(p+2,1);
168             p += 4;
169             for (; count; count--, p += 5)
170                 set_le32(p+1,IOT(object,my_base_address) + get_le32(p+1));
171         }
172         else
173             throwCantPack("unsupported bundle type in entry table");
174     }
175 
176     //if (Opt_debug) printf("%d entries encoded.\n",n);
177     UNUSED(n);
178 
179     soentries = ptr_diff(p, ientries) + 1;
180     oentries = ientries;
181     ientries = NULL;
182 }
183 
184 
readObjectTable()185 void PackWcle::readObjectTable()
186 {
187     LeFile::readObjectTable();
188 
189     // temporary copy of the object descriptors
190     iobject_desc.alloc(objects*sizeof(*iobject_table));
191     memcpy(iobject_desc,iobject_table,objects*sizeof(*iobject_table));
192 
193     unsigned ic,jc,virtual_size;
194 
195     for (ic = jc = virtual_size = 0; ic < objects; ic++)
196     {
197         jc += IOT(ic,npages);
198         IOT(ic,my_base_address) = virtual_size;
199         virtual_size += (IOT(ic,virtual_size)+mps-1) &~ (mps-1);
200     }
201     if (pages != jc)
202         throwCantPack("bad page number");
203 }
204 
205 
encodeObjectTable()206 void PackWcle::encodeObjectTable()
207 {
208     unsigned ic,jc;
209 
210     oobject_table = New(le_object_table_entry_t, soobject_table = 2);
211     memset(oobject_table,0,soobject_table * sizeof(*oobject_table));
212 
213     // object #1:
214     OOT(0,base_address) = IOT(0,base_address);
215 
216     ic = IOT(objects-1,my_base_address)+IOT(objects-1,virtual_size);
217     jc = pages*mps+sofixups+1024;
218     if (ic < jc)
219         ic = jc;
220 
221     unsigned csection = (ic + ph.overlap_overhead + mps-1) &~ (mps-1);
222 
223     OOT(0,virtual_size) = csection + mps;
224     OOT(0,flags) = LEOF_READ|LEOF_EXEC|LEOF_HUGE32|LEOF_PRELOAD;
225     OOT(0,pagemap_index) = 1;
226     OOT(0,npages) = opages;
227 
228     // object #2: stack
229     OOT(1,base_address) = (OOT(0,base_address)
230                                       +OOT(0,virtual_size)+mps-1) & ~(mps-1);
231     OOT(1,virtual_size) = mps + getDecompressorWrkmemSize();
232     OOT(1,flags) = LEOF_READ|LEOF_HUGE32|LEOF_WRITE;
233     OOT(1,pagemap_index) = 1;
234 
235     oh.init_cs_object = 1;
236     oh.init_eip_offset = neweip;
237     oh.init_ss_object = 2;
238     oh.init_esp_offset = OOT(1,virtual_size);
239     oh.automatic_data_object = 2;
240 }
241 
242 
encodePageMap()243 void PackWcle::encodePageMap()
244 {
245     opm_entries = New(le_pagemap_entry_t, sopm_entries = opages);
246     for (unsigned ic = 0; ic < sopm_entries; ic++)
247     {
248         opm_entries[ic].l = (unsigned char) (ic+1);
249         opm_entries[ic].m = (unsigned char) ((ic+1)>>8);
250         opm_entries[ic].h = 0;
251         opm_entries[ic].type = 0;
252     }
253 }
254 
255 
encodeFixupPageTable()256 void PackWcle::encodeFixupPageTable()
257 {
258     unsigned ic;
259     ofpage_table = New(unsigned, sofpage_table = 1 + opages);
260     for (ofpage_table[0] = ic = 0; ic < opages; ic++)
261         set_le32(ofpage_table+ic+1,sofixups-FIXUP_EXTRA);
262 }
263 
264 
encodeFixups()265 void PackWcle::encodeFixups()
266 {
267     ofixups = New(upx_byte, sofixups = 1*7 + FIXUP_EXTRA);
268     memset(ofixups,0,sofixups);
269     ofixups[0] = 7;
270     set_le16(ofixups+2,(LE_STUB_EDI + neweip) & (mps-1));
271     ofixups[4] = 1;
272 }
273 
274 
preprocessFixups()275 void PackWcle::preprocessFixups()
276 {
277     big_relocs = 0;
278 
279     unsigned ic,jc;
280 
281     Array(unsigned, counts, objects+2);
282     countFixups(counts);
283 
284     for (ic = jc = 0; ic < objects; ic++)
285         jc += counts[ic];
286 
287     if (jc == 0)
288     {
289         // FIXME: implement this
290         throwCantPack("files without relocations are not supported");
291     }
292 
293     ByteArray(rl, jc);
294     ByteArray(srf, counts[objects+0]+1);
295     ByteArray(slf, counts[objects+1]+1);
296 
297     upx_byte *selector_fixups = srf;
298     upx_byte *selfrel_fixups = slf;
299     unsigned rc = 0;
300 
301     upx_byte *fix = ifixups;
302     for (ic = jc = 0; ic < pages; ic++)
303     {
304         while ((unsigned)(fix - ifixups) < get_le32(ifpage_table+ic+1))
305         {
306             const int fixp2 = get_le16_signed(fix+2);
307             unsigned value;
308 
309             switch (*fix)
310             {
311                 case 2:       // selector fixup
312                     if (fixp2 < 0)
313                     {
314                         // cross page selector fixup
315                         dputc('S',stdout);
316                         fix += 5;
317                         break;
318                     }
319                     dputc('s',stdout);
320                     memcpy(selector_fixups,"\x8C\xCB\x66\x89\x9D",5); // mov bx, cs ; mov [xxx+ebp], bx
321                     if (IOT(fix[4]-1,flags) & LEOF_WRITE)
322                         selector_fixups[1] = 0xDB; // ds
323                     set_le32(selector_fixups+5,jc+fixp2);
324                     selector_fixups += 9;
325                     fix += 5;
326                     break;
327                 case 5:       // 16-bit offset
328                     if ((unsigned)fixp2 < 4096 && IOT(fix[4]-1,my_base_address) == jc)
329                         dputc('6',stdout);
330                     else
331                         throwCantPack("unsupported 16-bit offset relocation");
332                     fix += (fix[1] & 0x10) ? 9 : 7;
333                     break;
334                 case 6:       // 16:32 pointer
335                     if (fixp2 < 0)
336                     {
337                         // cross page pointer fixup
338                         dputc('P',stdout);
339                         fix += (fix[1] & 0x10) ? 9 : 7;
340                         break;
341                     }
342                     dputc('p',stdout);
343                     memcpy(iimage+jc+fixp2,fix+5,(fix[1] & 0x10) ? 4 : 2);
344                     set_le32(rl+4*rc++,jc+fixp2);
345                     set_le32(iimage+jc+fixp2,get_le32(iimage+jc+fixp2)+IOT(fix[4]-1,my_base_address));
346 
347                     memcpy(selector_fixups,"\x8C\xCA\x66\x89\x95",5);
348                     if (IOT(fix[4]-1,flags) & LEOF_WRITE)
349                         selector_fixups[1] = 0xDA; // ds
350                     set_le32(selector_fixups+5,jc+fixp2+4);
351                     selector_fixups += 9;
352                     fix += (fix[1] & 0x10) ? 9 : 7;
353                     break;
354                 case 7:       // 32-bit offset
355                     if (fixp2 < 0)
356                     {
357                         fix += (fix[1] & 0x10) ? 9 : 7;
358                         break;
359                     }
360                     //if (memcmp(iimage+jc+fixp2,fix+5,(fix[1] & 0x10) ? 4 : 2))
361                     //    throwCantPack("illegal fixup offset");
362 
363                     // work around a pmwunlite bug: remove duplicated fixups
364                     // FIXME: fix the other cases too
365                     if (rc == 0 || get_le32(rl+4*rc-4) != jc+fixp2)
366                     {
367                         set_le32(rl+4*rc++,jc+fixp2);
368                         set_le32(iimage+jc+fixp2,get_le32(iimage+jc+fixp2)+IOT(fix[4]-1,my_base_address));
369                     }
370                     fix += (fix[1] & 0x10) ? 9 : 7;
371                     break;
372                 case 8:       // 32-bit self relative fixup
373                     if (fixp2 < 0)
374                     {
375                         // cross page self relative fixup
376                         dputc('R',stdout);
377                         fix += (fix[1] & 0x10) ? 9 : 7;
378                         break;
379                     }
380                     value = get_le32(fix+5);
381                     if (fix[1] == 0)
382                         value &= 0xffff;
383                     set_le32(iimage+jc+fixp2,(value+IOT(fix[4]-1,my_base_address))-jc-fixp2-4);
384                     set_le32(selfrel_fixups,jc+fixp2);
385                     selfrel_fixups += 4;
386                     dputc('r',stdout);
387                     fix += (fix[1] & 0x10) ? 9 : 7;
388                     break;
389                 default:
390                     throwCantPack("unsupported fixup record");
391             }
392         }
393         jc += mps;
394     }
395 
396     // resize ifixups if it's too small
397     if (sofixups < 1000)
398     {
399         delete[] ifixups;
400         ifixups = new upx_byte[1000];
401     }
402     fix = optimizeReloc32 (rl,rc,ifixups,iimage,1,&big_relocs);
403     has_extra_code = srf != selector_fixups;
404     // FIXME: this could be removed if has_extra_code = false
405     // but then we'll need a flag
406     *selector_fixups++ = 0xC3; // ret
407     memcpy(fix,srf,selector_fixups-srf); // copy selector fixup code
408     fix += selector_fixups-srf;
409 
410     memcpy(fix,slf,selfrel_fixups-slf); // copy self-relative fixup positions
411     fix += selfrel_fixups-slf;
412     set_le32(fix,0xFFFFFFFFUL);
413     fix += 4;
414 
415     sofixups = ptr_diff(fix, ifixups);
416 }
417 
418 
419 #define RESERVED 0x1000
encodeImage(Filter * ft)420 void PackWcle::encodeImage(Filter *ft)
421 {
422     // concatenate image & preprocessed fixups
423     unsigned isize = soimage + sofixups;
424     ibuf.alloc(isize);
425     memcpy(ibuf,iimage,soimage);
426     memcpy(ibuf+soimage,ifixups,sofixups);
427 
428     delete[] ifixups; ifixups = NULL;
429 
430     oimage.allocForCompression(isize, RESERVED+512);
431     // prepare packheader
432     ph.u_len = isize;
433     // prepare filter [already done]
434     // compress
435     upx_compress_config_t cconf; cconf.reset();
436     cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack
437     compressWithFilters(ibuf, isize,
438                         oimage + RESERVED,
439                         ibuf + ft->addvalue, ft->buf_len,
440                         NULL, 0,
441                         ft, 512, &cconf, 0);
442 
443     ibuf.dealloc();
444     soimage = ph.c_len;
445     while (soimage & 3)
446         oimage[RESERVED + soimage++] = 0;
447 }
448 
449 
pack(OutputFile * fo)450 void PackWcle::pack(OutputFile *fo)
451 {
452     handleStub(fo);
453 
454     if (ih.byte_order || ih.word_order
455         || ih.exe_format_level
456         || ih.cpu_type < 2 || ih.cpu_type > 5
457         || ih.target_os != 1
458         || ih.module_type != 0x200
459         || ih.object_iterate_data_map_offset
460         || ih.resource_entries
461         || ih.module_directives_entries
462         || ih.imported_modules_count
463         || ih.object_table_entries > 255)
464         throwCantPack("watcom/le: unexpected value in header");
465 
466     readObjectTable();
467     readPageMap();
468     readResidentNames();
469     readEntryTable();
470     readFixupPageTable();
471     readFixups();
472     readImage();
473     readNonResidentNames();
474 
475 //    if (find_le32(iimage,20,get_le32("UPX ")) >= 0)
476     if (find_le32(iimage,UPX_MIN(soimage,256u),UPX_MAGIC_LE32) >= 0)
477         throwAlreadyPacked();
478 
479     if (ih.init_ss_object != objects)
480         throwCantPack("the stack is not in the last object");
481 
482     preprocessFixups();
483 
484     const unsigned text_size = IOT(ih.init_cs_object-1,npages) * mps;
485     const unsigned text_vaddr = IOT(ih.init_cs_object-1,my_base_address);
486 
487     // attach some useful data at the end of preprocessed fixups
488     ifixups[sofixups++] = (unsigned char) (ih.automatic_data_object & 0xff);
489     unsigned ic = objects*sizeof(*iobject_table);
490     memcpy(ifixups+sofixups,iobject_desc,ic);
491     iobject_desc.dealloc();
492 
493     sofixups += ic;
494     set_le32(ifixups+sofixups,ih.init_esp_offset+IOT(ih.init_ss_object-1,my_base_address)); // old stack pointer
495     set_le32(ifixups+sofixups+4,ih.init_eip_offset+text_vaddr); // real entry point
496     set_le32(ifixups+sofixups+8,mps*pages); // virtual address of unpacked relocations
497     ifixups[sofixups+12] = (unsigned char) (unsigned) objects;
498     sofixups += 13;
499 
500     // prepare filter
501     Filter ft(ph.level);
502     ft.buf_len = text_size;
503     ft.addvalue = text_vaddr;
504     // compress
505     encodeImage(&ft);
506 
507     const unsigned lsize = getLoaderSize();
508     neweip = getLoaderSection("WCLEMAIN");
509     int e_len = getLoaderSectionStart("WCLECUTP");
510     const unsigned d_len = lsize - e_len;
511     assert(e_len > 0 && e_len < RESERVED);
512 
513     memmove(oimage+e_len,oimage+RESERVED,soimage);
514     soimage += lsize;
515 
516     opages = (soimage+mps-1)/mps;
517     oh.bytes_on_last_page = soimage%mps;
518 
519     encodeObjectTable();
520     encodeFixups();
521     encodeFixupPageTable();
522     encodePageMap();
523     encodeEntryTable();
524 
525     encodeResidentNames();
526     encodeNonResidentNames();
527 
528     // patch loader
529     ic = (OOT(0,virtual_size) - d_len) &~ 15;
530     assert(ic > ((ph.u_len + ph.overlap_overhead + 31) &~ 15));
531 
532     linker->defineSymbol("WCLECUTP", ic);
533 
534     linker->defineSymbol("original_entry", ih.init_eip_offset + text_vaddr);
535     linker->defineSymbol("original_stack", ih.init_esp_offset +
536                          IOT(ih.init_ss_object - 1, my_base_address));
537     linker->defineSymbol("start_of_relocs", mps*pages);
538     defineDecompressorSymbols();
539     defineFilterSymbols(&ft);
540     linker->defineSymbol("filter_buffer_start", text_vaddr);
541 
542     unsigned jpos = (((ph.c_len + 3) &~ 3) + d_len + 3) / 4;
543     linker->defineSymbol("words_to_copy", jpos);
544     linker->defineSymbol("copy_dest", ((ic + d_len + 3) &~ 3) - 4);
545     linker->defineSymbol("copy_source", e_len + jpos * 4 - 4);
546 
547     relocateLoader();
548 
549     MemBuffer loader(lsize);
550     memcpy(loader, getLoader(), lsize);
551     patchPackHeader(loader, lsize);
552 
553     memcpy(oimage, loader, e_len);
554     memcpy(oimage + soimage - d_len, loader + e_len, d_len);
555 
556     writeFile(fo, opt->watcom_le.le);
557 
558     // verify
559     verifyOverlappingDecompression(oimage + e_len, oimage.getSize() - e_len);
560 
561     // copy the overlay
562     const unsigned overlaystart = ih.data_pages_offset + exe_offset
563         + getImageSize();
564     const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length;
565     checkOverlay(overlay);
566     copyOverlay(fo, overlay, &oimage);
567 
568     // finally check the compression ratio
569     if (!checkFinalCompressionRatio(fo))
570         throwNotCompressible();
571 }
572 
573 
574 /*************************************************************************
575 //
576 **************************************************************************/
577 
decodeFixups()578 void PackWcle::decodeFixups()
579 {
580     upx_byte *p = oimage + soimage;
581 
582     iimage.dealloc();
583 
584     MemBuffer tmpbuf;
585     unsigned fixupn = unoptimizeReloc32(&p,oimage,&tmpbuf,1);
586 
587     MemBuffer wrkmem(8*fixupn+8);
588     unsigned ic,jc,o,r;
589     for (ic=0; ic<fixupn; ic++)
590     {
591         jc=get_le32(tmpbuf+4*ic);
592         set_le32(wrkmem+ic*8,jc);
593         o = soobject_table;
594         r = get_le32(oimage+jc);
595         virt2rela(oobject_table,&o,&r);
596         set_le32(wrkmem+ic*8+4,OOT(o-1,my_base_address));
597         set_le32(oimage+jc,r);
598     }
599     set_le32(wrkmem+ic*8,0xFFFFFFFF);     // end of 32-bit offset fixups
600     tmpbuf.dealloc();
601 
602     // selector fixups and self-relative fixups
603     const upx_byte *selector_fixups = p;
604     const upx_byte *selfrel_fixups = p;
605 
606     while (*selfrel_fixups != 0xC3)
607         selfrel_fixups += 9;
608     selfrel_fixups++;
609     unsigned selectlen = ptr_diff(selfrel_fixups, selector_fixups)/9;
610 
611     ofixups = New(upx_byte, fixupn*9+1000+selectlen*5);
612     upx_bytep fp = ofixups;
613 
614     for (ic = 1, jc = 0; ic <= opages; ic++)
615     {
616         // self relative fixups
617         while ((r = get_le32(selfrel_fixups))/mps == ic-1)
618         {
619             fp[0] = 8;
620             set_le16(fp+2,r & (mps-1));
621             o = 4+get_le32(oimage+r);
622             set_le32(oimage+r,0);
623             r += o;
624             o = soobject_table;
625             virt2rela(oobject_table,&o,&r);
626             fp[4] = (unsigned char) o;
627             set_le32(fp+5,r);
628             fp[1] = (unsigned char) (r > 0xFFFF ? 0x10 : 0);
629             fp += fp[1] ? 9 : 7;
630             selfrel_fixups += 4;
631             dputc('r',stdout);
632         }
633         // selector fixups
634         while (selectlen && (r = get_le32(selector_fixups+5))/mps == ic-1)
635         {
636             fp[0] = 2;
637             fp[1] = 0;
638             set_le16(fp+2,r & (mps-1));
639             unsigned x = selector_fixups[1] > 0xD0 ? oh.init_ss_object : oh.init_cs_object;
640             fp[4] = (unsigned char) x;
641             fp += 5;
642             selector_fixups += 9;
643             selectlen--;
644             dputc('s',stdout);
645         }
646         // 32 bit offset fixups
647         while (get_le32(wrkmem+4*jc) < ic*mps)
648         {
649             if (jc > 1 && ((get_le32(wrkmem+4*(jc-2))+3) & (mps-1)) < 3) // cross page fixup?
650             {
651                 r = get_le32(oimage+get_le32(wrkmem+4*(jc-2)));
652                 fp[0] = 7;
653                 fp[1] = (unsigned char) (r > 0xFFFF ? 0x10 : 0);
654                 set_le16(fp+2,get_le32(wrkmem+4*(jc-2)) | ~3);
655                 set_le32(fp+5,r);
656                 o = soobject_table;
657                 r = get_le32(wrkmem+4*(jc-1));
658                 virt2rela(oobject_table,&o,&r);
659                 fp[4] = (unsigned char) o;
660                 fp += fp[1] ? 9 : 7;
661                 dputc('0',stdout);
662             }
663             o = soobject_table;
664             r = get_le32(wrkmem+4*(jc+1));
665             virt2rela(oobject_table,&o,&r);
666             r = get_le32(oimage+get_le32(wrkmem+4*jc));
667             fp[0] = 7;
668             fp[1] = (unsigned char) (r > 0xFFFF ? 0x10 : 0);
669             set_le16(fp+2,get_le32(wrkmem+4*jc) & (mps-1));
670             fp[4] = (unsigned char) o;
671             set_le32(fp+5,r);
672             fp += fp[1] ? 9 : 7;
673             jc += 2;
674         }
675         set_le32(ofpage_table+ic,ptr_diff(fp,ofixups));
676     }
677     for (ic=0; ic < FIXUP_EXTRA; ic++)
678         *fp++ = 0;
679     sofixups = ptr_diff(fp, ofixups);
680 }
681 
682 
decodeFixupPageTable()683 void PackWcle::decodeFixupPageTable()
684 {
685     ofpage_table = New(unsigned, sofpage_table = 1 + opages);
686     set_le32(ofpage_table,0);
687     // the rest of ofpage_table is filled by decodeFixups()
688 }
689 
690 
decodeObjectTable()691 void PackWcle::decodeObjectTable()
692 {
693     soobject_table = oimage[ph.u_len - 1];
694     oobject_table = New(le_object_table_entry_t, soobject_table);
695     unsigned jc, ic = soobject_table * sizeof(*oobject_table);
696 
697     const unsigned extradata = ph.version == 10 ? 17 : 13;
698     memcpy(oobject_table,oimage + ph.u_len - extradata - ic,ic);
699     if (ph.version >= 12)
700         oh.automatic_data_object = oimage[ph.u_len - ic - 14];
701 
702     for (ic = jc = 0; ic < soobject_table; ic++)
703     {
704         OOT(ic,my_base_address) = jc;
705         jc += (OOT(ic,virtual_size)+mps-1) &~ (mps-1);
706     }
707 
708     // restore original cs:eip & ss:esp
709     ic = soobject_table;
710     jc = get_le32(oimage + ph.u_len - (ph.version < 11 ? 13 : 9));
711     virt2rela(oobject_table,&ic,&jc);
712     oh.init_cs_object = ic;
713     oh.init_eip_offset = jc;
714 
715     ic = soobject_table;
716     if (ph.version < 10)
717         jc = ih.init_esp_offset;
718     else
719         jc = get_le32(oimage + ph.u_len - (ph.version == 10 ? 17 : 13));
720     virt2rela(oobject_table,&ic,&jc);
721     oh.init_ss_object = ic;
722     oh.init_esp_offset = jc;
723 }
724 
725 
decodeImage()726 void PackWcle::decodeImage()
727 {
728     oimage.allocForUncompression(ph.u_len);
729 
730     decompress(iimage + ph.buf_offset + ph.getPackHeaderSize(),oimage);
731     soimage = get_le32(oimage + ph.u_len - 5);
732     opages = soimage / mps;
733     oh.memory_page_size = mps;
734 }
735 
736 
decodeEntryTable()737 void PackWcle::decodeEntryTable()
738 {
739     unsigned count,object,n,r;
740     upx_byte *p = ientries;
741     n = 0;
742     while (*p)
743     {
744         count = *p;
745         n += count;
746         if (p[1] == 0) // unused bundle
747             p += 2;
748         else if (p[1] == 3) // 32-bit offset bundle
749         {
750             object = get_le16(p+2);
751             if (object != 1)
752                 throwCantUnpack("corrupted entry found");
753             object = soobject_table;
754             r = get_le32(p+5);
755             virt2rela(oobject_table,&object,&r);
756             set_le16(p+2,object--);
757             p += 4;
758             for (; count; count--, p += 5)
759                 set_le32(p+1,get_le32(p+1) - OOT(object,my_base_address));
760         }
761         else
762             throwCantUnpack("unsupported bundle type in entry table");
763     }
764 
765     //if (Opt_debug) printf("\n%d entries decoded.\n",n);
766     UNUSED(n);
767 
768     soentries = ptr_diff(p, ientries) + 1;
769     oentries = ientries;
770     ientries = NULL;
771 }
772 
773 
canUnpack()774 int PackWcle::canUnpack()
775 {
776     if (!LeFile::readFileHeader())
777         return false;
778     fi->seek(exe_offset + ih.data_pages_offset, SEEK_SET);
779     // FIXME: 1024 could be too large for some files
780     //int len = 1024;
781     int len = UPX_MIN(getImageSize(), 256u);
782     if (len == 0)
783         return false;
784     return readPackHeader(len) ? 1 : -1;
785 }
786 
787 
virt2rela(const le_object_table_entry_t * entr,unsigned * objn,unsigned * addr)788 void PackWcle::virt2rela(const le_object_table_entry_t *entr,unsigned *objn,unsigned *addr)
789 {
790     for (; *objn > 1; objn[0]--)
791     {
792         if (entr[*objn-1].my_base_address > *addr)
793             continue;
794         *addr -= entr[*objn-1].my_base_address;
795         break;
796     }
797 }
798 
799 
800 /*************************************************************************
801 //
802 **************************************************************************/
803 
unpack(OutputFile * fo)804 void PackWcle::unpack(OutputFile *fo)
805 {
806     handleStub(fo);
807 
808     readObjectTable();
809     iobject_desc.dealloc();
810     readPageMap();
811     readResidentNames();
812     readEntryTable();
813     readFixupPageTable();
814     readFixups();
815     readImage();
816     readNonResidentNames();
817 
818     decodeImage();
819     decodeObjectTable();
820 
821     // unfilter
822     if (ph.filter)
823     {
824         const unsigned text_size = OOT(oh.init_cs_object-1,npages) * mps;
825         const unsigned text_vaddr = OOT(oh.init_cs_object-1,my_base_address);
826 
827         Filter ft(ph.level);
828         ft.init(ph.filter, text_vaddr);
829         ft.cto = (unsigned char) ph.filter_cto;
830         if (ph.version < 11)
831             ft.cto = (unsigned char) (get_le32(oimage+ph.u_len-9) >> 24);
832         ft.unfilter(oimage+text_vaddr, text_size);
833     }
834 
835     decodeFixupPageTable();
836     decodeFixups();
837     decodeEntryTable();
838     decodePageMap();
839     decodeResidentNames();
840     decodeNonResidentNames();
841 
842     for (unsigned ic = 0; ic < soobject_table; ic++)
843         OOT(ic,my_base_address) = 0;
844 
845     while (oimage[soimage-1] == 0)
846         soimage--;
847     oh.bytes_on_last_page = soimage % mps;
848 
849     // write decompressed file
850     if (fo)
851         writeFile(fo, opt->watcom_le.le);
852 
853     // copy the overlay
854     const unsigned overlaystart = ih.data_pages_offset + exe_offset
855         + getImageSize();
856     const unsigned overlay = file_size - overlaystart - ih.non_resident_name_table_length;
857     checkOverlay(overlay);
858     copyOverlay(fo, overlay, &oimage);
859 }
860 
861 /* vim:set ts=4 sw=4 et: */
862