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