1 /* p_exe.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 "p_exe.h"
34 #include "linker.h"
35
36 static const
37 #include "stub/i086-dos16.exe.h"
38
39 #define RSFCRI 4096 // Reserved Space For Compressed Relocation Info
40 #define MAXMATCH 0x2000
41 #define MAXRELOCS (0x8000-MAXMATCH)
42
43 #define DI_LIMIT 0xff00 // see the assembly why
44
45
46 /*************************************************************************
47 //
48 **************************************************************************/
49
PackExe(InputFile * f)50 PackExe::PackExe(InputFile *f) :
51 super(f)
52 {
53 bele = &N_BELE_RTP::le_policy;
54 COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 32)
55 COMPILE_TIME_ASSERT_ALIGNED1(exe_header_t)
56 ih_exesize = ih_imagesize = ih_overlay = 0;
57 stack_for_lzma = 0;
58 use_clear_dirty_stack = false;
59 }
60
61
getCompressionMethods(int method,int level) const62 const int *PackExe::getCompressionMethods(int method, int level) const
63 {
64 bool small = ih_imagesize <= 256*1024;
65 // disable lzma for "--brute" unless explicitly given "--lzma"
66 // WARNING: this side effect persists for later files!
67 if (opt->all_methods_use_lzma && !opt->method_lzma_seen)
68 opt->all_methods_use_lzma = false;
69 return Packer::getDefaultCompressionMethods_8(method, level, small);
70 }
71
72
getFilters() const73 const int *PackExe::getFilters() const
74 {
75 return NULL;
76 }
77
78
fillExeHeader(struct exe_header_t * eh) const79 int PackExe::fillExeHeader(struct exe_header_t *eh) const
80 {
81 #define oh (*eh)
82 // fill new exe header
83 int flag = 0;
84 if (!opt->dos_exe.no_reloc && !M_IS_LZMA(ph.method))
85 flag |= USEJUMP;
86 if (ih.relocs == 0)
87 flag |= NORELOC;
88
89 memset(&oh,0,sizeof(oh));
90 oh.ident = 'M' + 'Z' * 256;
91 oh.headsize16 = 2;
92
93 unsigned minsp = 0x200;
94 if (M_IS_LZMA(ph.method))
95 minsp = stack_for_lzma;
96 minsp = ALIGN_UP(minsp, 16u);
97 assert(minsp < 0xff00);
98 if (oh.sp > minsp)
99 minsp = oh.sp;
100 if (minsp < 0xff00 - 2)
101 minsp = ALIGN_UP(minsp, 2u);
102 oh.sp = minsp;
103
104 unsigned destpara = (ph.u_len + ph.overlap_overhead - ph.c_len + 31) / 16;
105 oh.ss = ph.c_len/16 + destpara;
106 if (ih.ss*16 + ih.sp < 0x100000 && ih.ss > oh.ss && ih.sp > 0x200)
107 oh.ss = ih.ss;
108 if (oh.ss*16 + 0x50 < ih.ss*16 + ih.sp
109 && oh.ss*16 + 0x200 > ih.ss*16 + ih.sp)
110 oh.ss += 0x20;
111
112 if (oh.ss != ih.ss)
113 flag |= SS;
114 if (oh.sp != ih.sp || M_IS_LZMA(ph.method))
115 flag |= SP;
116 return flag;
117 #undef oh
118 }
119
addLoaderEpilogue(int flag)120 void PackExe::addLoaderEpilogue(int flag)
121 {
122 addLoader("EXEMAIN5", NULL);
123 if (relocsize)
124 addLoader(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? "EXENOADJ" : "EXEADJUS",
125 "EXERELO1",
126 has_9a ? "EXEREL9A" : "",
127 "EXERELO2",
128 ih_exesize > 0xFE00 ? "EXEREBIG" : "",
129 "EXERELO3",
130 NULL
131 );
132 addLoader("EXEMAIN8",
133 device_driver ? "DEVICEEND" : "",
134 (flag & SS) ? "EXESTACK" : "",
135 (flag & SP) ? "EXESTASP" : "",
136 (flag & USEJUMP) ? "EXEJUMPF" : "",
137 NULL
138 );
139 if (!(flag & USEJUMP))
140 addLoader(ih.cs ? "EXERCSPO" : "",
141 "EXERETIP",
142 NULL
143 );
144
145 linker->defineSymbol("original_cs", ih.cs);
146 linker->defineSymbol("original_ip", ih.ip);
147 linker->defineSymbol("original_sp", ih.sp);
148 linker->defineSymbol("original_ss", ih.ss);
149 linker->defineSymbol("reloc_size",
150 (ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff)
151 >= relocsize ? 0 : MAXRELOCS) - relocsize);
152 }
153
buildLoader(const Filter *)154 void PackExe::buildLoader(const Filter *)
155 {
156 // get flag
157 exe_header_t dummy_oh;
158 int flag = fillExeHeader(&dummy_oh);
159
160 initLoader(stub_i086_dos16_exe, sizeof(stub_i086_dos16_exe));
161
162 if (M_IS_LZMA(ph.method))
163 {
164 addLoader("LZMA_DEC00",
165 opt->small ? "LZMA_DEC10" : "LZMA_DEC20",
166 "LZMA_DEC30",
167 use_clear_dirty_stack ? "LZMA_DEC31" : "",
168 "LZMA_DEC32",
169 ph.u_len > 0xffff ? "LZMA_DEC33" : "",
170 NULL
171 );
172
173 addLoaderEpilogue(flag);
174 defineDecompressorSymbols();
175 const unsigned lsize0 = getLoaderSize();
176
177 // Lzma decompression code starts at ss:0x10, and its size is
178 // lsize bytes. It also needs getDecompressorWrkmemSize() bytes
179 // during uncompression. It also uses some stack, so 0x100
180 // more bytes are allocated
181 stack_for_lzma = 0x10 + lsize0 + getDecompressorWrkmemSize() + 0x100;
182 stack_for_lzma = ALIGN_UP(stack_for_lzma, 16u);
183
184 unsigned clear_dirty_stack_low = 0x10 + lsize0;
185 clear_dirty_stack_low = ALIGN_UP(clear_dirty_stack_low, 2u);
186 if (use_clear_dirty_stack)
187 linker->defineSymbol("clear_dirty_stack_low", clear_dirty_stack_low);
188
189 relocateLoader();
190 const unsigned lsize = getLoaderSize();
191 assert(lsize0 == lsize);
192 MemBuffer loader(lsize);
193 memcpy(loader, getLoader(), lsize);
194
195 MemBuffer compressed_lzma;
196 compressed_lzma.allocForCompression(lsize);
197 unsigned c_len_lzma = MemBuffer::getSizeForCompression(lsize);
198 int r = upx_compress(loader, lsize, compressed_lzma, &c_len_lzma,
199 NULL, M_NRV2B_LE16, 9, NULL, NULL);
200 assert(r == UPX_E_OK); assert(c_len_lzma < lsize);
201
202 info("lzma+relocator code compressed: %u -> %u", lsize, c_len_lzma);
203 // reinit the loader
204 initLoader(stub_i086_dos16_exe, sizeof(stub_i086_dos16_exe));
205 // prepare loader
206 if (device_driver)
207 addLoader("DEVICEENTRY,LZMADEVICE,DEVICEENTRY2", NULL);
208
209 linker->addSection("COMPRESSED_LZMA", compressed_lzma, c_len_lzma, 0);
210 addLoader("LZMAENTRY,NRV2B160,NRVDDONE,NRVDECO1,NRVGTD00,NRVDECO2",
211 NULL);
212
213 }
214 else if (device_driver)
215 addLoader("DEVICEENTRY,DEVICEENTRY2", NULL);
216
217 addLoader("EXEENTRY",
218 M_IS_LZMA(ph.method) && device_driver ? "LONGSUB" : "SHORTSUB",
219 "JNCDOCOPY",
220 relocsize ? "EXERELPU" : "",
221 "EXEMAIN4",
222 M_IS_LZMA(ph.method) ? "" : "EXEMAIN4B",
223 "EXEMAIN4C",
224 M_IS_LZMA(ph.method) ? "COMPRESSED_LZMA_START,COMPRESSED_LZMA" : "",
225 "+G5DXXXX,UPX1HEAD,EXECUTPO",
226 NULL
227 );
228 if (ph.method == M_NRV2B_8)
229 addLoader("NRV2B16S", // decompressor
230 ph.u_len > DI_LIMIT ? "N2B64K01" : "",
231 "NRV2BEX1",
232 opt->cpu == opt->CPU_8086 ? "N2BX8601" : "N2B28601",
233 "NRV2BEX2",
234 opt->cpu == opt->CPU_8086 ? "N2BX8602" : "N2B28602",
235 "NRV2BEX3",
236 ph.c_len > 0xffff ? "N2B64K02" : "",
237 "NRV2BEX9",
238 NULL
239 );
240 else if (ph.method == M_NRV2D_8)
241 addLoader("NRV2D16S",
242 ph.u_len > DI_LIMIT ? "N2D64K01" : "",
243 "NRV2DEX1",
244 opt->cpu == opt->CPU_8086 ? "N2DX8601" : "N2D28601",
245 "NRV2DEX2",
246 opt->cpu == opt->CPU_8086 ? "N2DX8602" : "N2D28602",
247 "NRV2DEX3",
248 ph.c_len > 0xffff ? "N2D64K02" : "",
249 "NRV2DEX9",
250 NULL
251 );
252 else if (ph.method == M_NRV2E_8)
253 addLoader("NRV2E16S",
254 ph.u_len > DI_LIMIT ? "N2E64K01" : "",
255 "NRV2EEX1",
256 opt->cpu == opt->CPU_8086 ? "N2EX8601" : "N2E28601",
257 "NRV2EEX2",
258 opt->cpu == opt->CPU_8086 ? "N2EX8602" : "N2E28602",
259 "NRV2EEX3",
260 ph.c_len > 0xffff ? "N2E64K02" : "",
261 "NRV2EEX9",
262 NULL
263 );
264 else if M_IS_LZMA(ph.method)
265 return;
266 else
267 throwInternalError("unknown compression method");
268
269 addLoaderEpilogue(flag);
270 }
271
272
273 /*************************************************************************
274 //
275 **************************************************************************/
276
readFileHeader()277 int PackExe::readFileHeader()
278 {
279 ih_exesize = ih_imagesize = ih_overlay = 0;
280 fi->readx(&ih,sizeof(ih));
281 if (ih.ident != 'M' + 'Z'*256 && ih.ident != 'Z' + 'M'*256)
282 return 0;
283 ih_exesize = ih.m512 + ih.p512*512 - (ih.m512 ? 512 : 0);
284 if (!ih_exesize) {
285 ih_exesize = file_size;
286 }
287 ih_imagesize = ih_exesize - ih.headsize16*16;
288 ih_overlay = file_size - ih_exesize;
289 if (file_size < (int)sizeof(ih)
290 || ((ih.m512 | ih.p512) && ih.m512+ih.p512*512u < sizeof (ih)))
291 throwCantPack("illegal exe header");
292 if (file_size < (off_t)ih_exesize || ih_imagesize <= 0 || ih_imagesize > ih_exesize)
293 throwCantPack("exe header corrupted");
294 #if 0
295 printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay);
296 #endif
297 return UPX_F_DOS_EXE;
298 }
299
300
canPack()301 bool PackExe::canPack()
302 {
303 if (fn_has_ext(fi->getName(),"sys"))
304 return false;
305 if (!readFileHeader())
306 return false;
307 if (file_size < 1024)
308 throwCantPack("file is too small");
309 fi->seek(0x3c,SEEK_SET);
310 LE32 offs;
311 fi->readx(&offs,sizeof (offs));
312 if (ih.relocoffs >= 0x40 && offs)
313 {
314 if (opt->dos_exe.force_stub)
315 opt->overlay = opt->COPY_OVERLAY;
316 else
317 throwCantPack("can't pack new-exe");
318 }
319 return true;
320 }
321
322
323 /*************************************************************************
324 //
325 **************************************************************************/
326
327 static
optimize_relocs(upx_byte * b,const unsigned size,const upx_byte * relocs,const unsigned nrelocs,upx_byte * crel,bool * has_9a)328 unsigned optimize_relocs(upx_byte *b, const unsigned size,
329 const upx_byte *relocs, const unsigned nrelocs,
330 upx_byte *crel, bool *has_9a)
331 {
332 if (opt->exact)
333 throwCantPackExact();
334
335 upx_byte * const crel_save = crel;
336 unsigned i;
337 unsigned seg_high = 0;
338 #if 0
339 unsigned seg_low = 0xffffffff;
340 unsigned off_low = 0xffffffff;
341 unsigned off_high = 0;
342 unsigned linear_low = 0xffffffff;
343 unsigned linear_high = 0;
344 #endif
345
346 // pass 1 - find 0x9a bounds
347 for (i = 0; i < nrelocs; i++)
348 {
349 unsigned addr = get_le32(relocs+4*i);
350 if (addr >= size - 1)
351 throwCantPack("unexpected relocation 1");
352 if (addr >= 3 && b[addr-3] == 0x9a)
353 {
354 unsigned seg = get_le16(b+addr);
355 if (seg > seg_high)
356 seg_high = seg;
357 #if 0
358 if (seg < seg_low)
359 seg_low = seg;
360 unsigned off = get_le16(b+addr-2);
361 if (off < off_low)
362 off_low = off;
363 if (off > off_high)
364 off_high = off;
365 unsigned l = (seg << 4) + off;
366 if (l < linear_low)
367 linear_low = l;
368 if (l > linear_high)
369 linear_high = l;
370 #endif
371 }
372 }
373 //printf("%d %d\n", seg_low, seg_high);
374 //printf("%d %d\n", off_low, off_high);
375 //printf("%d %d\n", linear_low, linear_high);
376
377
378 // pass 2 - reloc
379
380 crel += 4; // to be filled in later
381
382 unsigned ones = 0;
383 unsigned es = 0, di, t;
384 i = 0;
385 do
386 {
387 unsigned addr = get_le32(relocs+4*i);
388 set_le16(crel,di = addr & 0x0f);
389 set_le16(crel+2,(addr >> 4) - es);
390 es = addr >> 4;
391 crel += 4;
392
393 for (++i; i < nrelocs; i++)
394 {
395 addr = get_le32(relocs+4*i);
396 //printf ("%x\n",es*16+di);
397 if ((addr - es*16 > 0xfffe)
398 || (i == nrelocs - 1 && addr - es * 16 > 0xff00)
399 )
400 {
401 // segment change
402 t = 1+(0xffff-di)/254;
403 memset(crel,1,t);
404 crel += t;
405 ones += t-1; // -1 is used to help the assembly stuff
406 break;
407 }
408 unsigned offs = addr - es*16;
409 if (offs >= 3 && b[es*16 + offs-3] == 0x9a && offs > di + 3)
410 {
411 for (t = di; t < offs-3; t++)
412 if (b[es*16+t] == 0x9a && get_le16(b+es*16+t+3) <= seg_high)
413 break;
414 if (t == offs-3)
415 {
416 // code 0: search for 0x9a
417 *crel++ = 0;
418 di = offs;
419 *has_9a = true;
420 continue;
421 }
422 }
423 t = offs - di;
424 if (t < 2)
425 throwCantPack("unexpected relocation 2");
426
427 while (t >= 256)
428 {
429 // code 1: add 254, don't reloc
430 *crel++ = 1;
431 t -= 254;
432 ones++;
433 }
434 *crel++ = (unsigned char) t;
435 di = offs;
436 }
437 } while (i < nrelocs);
438 *crel++ = 1;
439 ones++;
440 set_le16 (crel_save,ones);
441 set_le16 (crel_save+2,seg_high);
442
443 //OutputFile::dump("x.rel", crel_save, crel - crel_save);
444 return (unsigned) (crel - crel_save);
445 }
446
447
448 /*************************************************************************
449 //
450 **************************************************************************/
451
pack(OutputFile * fo)452 void PackExe::pack(OutputFile *fo)
453 {
454 unsigned ic;
455
456 if (ih.relocs > MAXRELOCS)
457 throwCantPack("too many relocations");
458 checkOverlay(ih_overlay);
459
460 // alloc buffers
461 relocsize = RSFCRI + 4*ih.relocs;
462 ibuf.alloc(ih_imagesize+16+relocsize+2);
463 obuf.allocForCompression(ih_imagesize+16+relocsize+2);
464
465 // read image
466 fi->seek(ih.headsize16*16,SEEK_SET);
467 fi->readx(ibuf,ih_imagesize);
468
469 checkAlreadyPacked(ibuf, UPX_MIN(ih_imagesize, 127u));
470
471 device_driver = get_le32(ibuf) == 0xffffffffu;
472
473 // relocations
474 has_9a = false;
475 upx_byte *w = ibuf + ih_imagesize;
476 if (ih.relocs)
477 {
478 upx_byte *wr = w + RSFCRI;
479
480 fi->seek(ih.relocoffs,SEEK_SET);
481 fi->readx(wr,4*ih.relocs);
482
483 for (ic = 0; ic < ih.relocs; ic++)
484 {
485 unsigned jc = get_le32(wr+4*ic);
486 set_le32(wr+4*ic, ((jc>>16)*16+(jc&0xffff)) & 0xfffff);
487 }
488 qsort(wr,ih.relocs,4,le32_compare);
489 relocsize = optimize_relocs(ibuf, ih_imagesize, wr, ih.relocs, w, &has_9a);
490 set_le16(w+relocsize, relocsize+2);
491 relocsize += 2;
492 if (relocsize > MAXRELOCS)
493 throwCantPack("too many relocations");
494 #if 0
495 upx_byte out[9*relocsize/8+1024];
496 unsigned in_len = relocsize;
497 unsigned out_len = 0;
498 ucl_nrv2b_99_compress(w, in_len, out, &out_len, NULL, 9, NULL, NULL);
499 printf("reloc compress: %d -> %d\n", in_len, out_len);
500 #endif
501 }
502 else
503 {
504 relocsize = 0;
505 }
506
507 // prepare packheader
508 ph.u_len = ih_imagesize + relocsize;
509 // prepare filter
510 Filter ft(ph.level);
511 // compress (max_match = 8192)
512 upx_compress_config_t cconf; cconf.reset();
513 cconf.conf_ucl.max_match = MAXMATCH;
514 cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28 KiB stack
515 compressWithFilters(&ft, 32, &cconf);
516
517 if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
518 if (ph.max_run_found + ph.max_match_found > 0x8000)
519 throwCantPack("decompressor limit exceeded, send a bugreport");
520
521 #if TESTING
522 if (opt->debug.debug_level)
523 {
524 printf("image+relocs %d -> %d\n",ih_imagesize+relocsize,ph.c_len);
525 printf("offsets: %d - %d\nmatches: %d - %d\nruns: %d - %d\n",
526 0/*ph.min_offset_found*/,ph.max_offset_found,
527 0/*ph.min_match_found*/,ph.max_match_found,
528 0/*ph.min_run_found*/,ph.max_run_found);
529 }
530 #endif
531
532 int flag = fillExeHeader(&oh);
533
534 const unsigned lsize = getLoaderSize();
535 MemBuffer loader(lsize);
536 memcpy(loader,getLoader(),lsize);
537 //OutputFile::dump("xxloader.dat", loader, lsize);
538
539 // patch loader
540 const unsigned packedsize = ph.c_len;
541 const unsigned e_len = getLoaderSectionStart("EXECUTPO");
542 const unsigned d_len = lsize - e_len;
543 assert((e_len&15) == 0);
544
545 const unsigned copysize = (1+packedsize+d_len) & ~1;
546 const unsigned firstcopy = copysize%0x10000 ? copysize%0x10000 : 0x10000;
547
548 // set oh.min & oh.max
549 ic = ih.min*16 + ih_imagesize;
550 if (ic < oh.ss*16u + oh.sp)
551 ic = oh.ss*16u + oh.sp;
552 oh.min = (ic - (packedsize + lsize)) / 16;
553 ic = oh.min + (ih.max - ih.min);
554 oh.max = ic < 0xffff && ih.max != 0xffff ? ic : 0xffff;
555
556 // set extra info
557 unsigned char extra_info[9];
558 unsigned eisize = 0;
559 if (oh.ss != ih.ss)
560 {
561 set_le16(extra_info+eisize,ih.ss);
562 eisize += 2;
563 assert((flag & SS) != 0); // set in fillExeHeader()
564 }
565 if (oh.sp != ih.sp)
566 {
567 set_le16(extra_info+eisize,ih.sp);
568 eisize += 2;
569 assert((flag & SP) != 0); // set in fillExeHeader()
570 }
571 if (ih.min != oh.min)
572 {
573 set_le16(extra_info+eisize,ih.min);
574 eisize += 2;
575 flag |= MINMEM;
576 }
577 if (ih.max != oh.max)
578 {
579 set_le16(extra_info+eisize,ih.max);
580 eisize += 2;
581 flag |= MAXMEM;
582 }
583 extra_info[eisize++] = (unsigned char) flag;
584
585 if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
586 linker->defineSymbol("bx_magic", 0x7FFF + 0x10 * ((packedsize & 15) + 1));
587
588 unsigned decompressor_entry = 1 + (packedsize & 15);
589 if (M_IS_LZMA(ph.method))
590 decompressor_entry = 0x10;
591 linker->defineSymbol("decompressor_entry", decompressor_entry);
592
593 // patch loader
594 if (flag & USEJUMP)
595 {
596 // I use a relocation entry to set the original cs
597 unsigned n = getLoaderSectionStart("EXEJUMPF") + 1;
598 n += packedsize + 2;
599 oh.relocs = 1;
600 oh.firstreloc = (n & 0xf) + ((n >> 4) << 16);
601 }
602 else
603 {
604 oh.relocs = 0;
605 oh.firstreloc = ih.cs * 0x10000 + ih.ip;
606 }
607
608 // g++ 3.1 does not like the following line...
609 // oh.relocoffs = offsetof(exe_header_t, firstreloc);
610 oh.relocoffs = ptr_diff(&oh.firstreloc, &oh);
611
612 linker->defineSymbol("destination_segment", oh.ss - ph.c_len / 16 - e_len / 16);
613 linker->defineSymbol("source_segment", e_len / 16 + (copysize - firstcopy) / 16);
614 linker->defineSymbol("copy_offset", firstcopy - 2);
615 linker->defineSymbol("words_to_copy",firstcopy / 2);
616
617 linker->defineSymbol("exe_stack_sp", oh.sp);
618 linker->defineSymbol("exe_stack_ss", oh.ss);
619 linker->defineSymbol("interrupt", get_le16(ibuf + 8));
620 linker->defineSymbol("attribute", get_le16(ibuf + 4));
621 linker->defineSymbol("orig_strategy", get_le16(ibuf + 6));
622
623 const unsigned outputlen = sizeof(oh)+lsize+packedsize+eisize;
624 oh.m512 = outputlen & 511;
625 oh.p512 = (outputlen + 511) >> 9;
626
627 const char *exeentry = M_IS_LZMA(ph.method) ? "LZMAENTRY" : "EXEENTRY";
628 oh.ip = device_driver ? getLoaderSection(exeentry) - 2 : 0;
629
630 defineDecompressorSymbols();
631 relocateLoader();
632 memcpy(loader, getLoader(), lsize);
633 patchPackHeader(loader,e_len);
634
635 //fprintf(stderr,"\ne_len=%x d_len=%x c_len=%x oo=%x ulen=%x destp=%x copys=%x images=%x",e_len,d_len,packedsize,ph.overlap_overhead,ph.u_len,destpara,copysize,ih_imagesize);
636
637 // write header + write loader + compressed file
638 #if TESTING
639 if (opt->debug.debug_level)
640 printf("\n%d %d %d %d\n",(int)sizeof(oh),e_len,packedsize,d_len);
641 #endif
642 fo->write(&oh,sizeof(oh));
643 fo->write(loader,e_len); // entry
644 fo->write(obuf,packedsize);
645 fo->write(loader+e_len,d_len); // decompressor
646 fo->write(extra_info,eisize);
647 assert(eisize <= 9);
648 #if 0
649 printf("%-13s: program hdr : %8ld bytes\n", getName(), (long) sizeof(oh));
650 printf("%-13s: entry : %8ld bytes\n", getName(), (long) e_len);
651 printf("%-13s: compressed : %8ld bytes\n", getName(), (long) packedsize);
652 printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) d_len);
653 printf("%-13s: extra info : %8ld bytes\n", getName(), (long) eisize);
654 #endif
655
656 // verify
657 verifyOverlappingDecompression();
658
659 // copy the overlay
660 copyOverlay(fo, ih_overlay, &obuf);
661 //fprintf (stderr,"%x %x\n",relocsize,ph.u_len);
662
663 // finally check the compression ratio
664 if (!checkFinalCompressionRatio(fo))
665 throwNotCompressible();
666 }
667
668
669 /*************************************************************************
670 //
671 **************************************************************************/
672
canUnpack()673 int PackExe::canUnpack()
674 {
675 if (!readFileHeader())
676 return false;
677 const off_t off = ih.headsize16 * 16;
678 fi->seek(off, SEEK_SET);
679 bool b = readPackHeader(4096);
680 return b && (off + (off_t) ph.c_len <= file_size);
681 }
682
683
684 /*************************************************************************
685 //
686 **************************************************************************/
687
unpack(OutputFile * fo)688 void PackExe::unpack(OutputFile *fo)
689 {
690 ibuf.alloc(file_size);
691 obuf.allocForUncompression(ph.u_len);
692
693 // read the file
694 fi->seek(ih.headsize16*16,SEEK_SET);
695 fi->readx(ibuf,ih_imagesize);
696
697 // get compressed data offset
698 unsigned e_len = ph.buf_offset + ph.getPackHeaderSize();
699 if (ih_imagesize <= e_len + ph.c_len)
700 throwCantUnpack("file damaged");
701
702 checkOverlay(ih_overlay);
703
704 // decompress
705 decompress(ibuf+e_len,obuf);
706
707 unsigned imagesize = ih_imagesize;
708 imagesize--;
709 const unsigned char flag = ibuf[imagesize];
710
711 unsigned relocn = 0;
712 upx_byte *relocs = obuf + ph.u_len;
713
714 MemBuffer wrkmem;
715 if (!(flag & NORELOC))
716 {
717 relocs -= get_le16(obuf+ph.u_len-2);
718 ph.u_len -= 2;
719
720 wrkmem.alloc(4*MAXRELOCS);
721 unsigned es = 0, ones = get_le16(relocs);
722 const unsigned seghi = get_le16(relocs+2);
723 const upx_byte *p = relocs + 4;
724
725 while (ones)
726 {
727 unsigned di = get_le16(p);
728 es += get_le16(p+2);
729 bool dorel = true;
730 for (p += 4; ones && di < 0x10000; p++)
731 {
732 if (dorel)
733 {
734 set_le16(wrkmem+4*relocn,di);
735 set_le16(wrkmem+2+4*relocn++,es);
736 //printf ("%x\n",es*16+di);
737 }
738 dorel = true;
739 if (*p == 0)
740 {
741 const upx_byte *q;
742 for (q = obuf+es*16+di; !(*q == 0x9a && get_le16(q+3) <= seghi); q++)
743 ;
744 di = ptr_diff(q, obuf+es*16) + 3;
745 }
746 else if (*p == 1)
747 {
748 di += 254;
749 if (di < 0x10000)
750 ones--;
751 dorel = false;
752 }
753 else
754 di += *p;
755 }
756 }
757 }
758
759 // fill new exe header
760 memset(&oh,0,sizeof(oh));
761 oh.ident = 'M' + 'Z'*256;
762
763 if (relocn)
764 {
765 oh.relocs = relocn;
766 while (relocn & 3)
767 set_le32(wrkmem+4*relocn++,0);
768 }
769
770 unsigned outputlen = ptr_diff(relocs, obuf) + sizeof(oh) + relocn*4;
771 oh.m512 = outputlen & 511;
772 oh.p512 = (outputlen + 511) >> 9;
773 oh.headsize16 = 2+relocn/4;
774
775 oh.max = ih.max;
776 oh.min = ih.min;
777 oh.sp = ih.sp;
778 oh.ss = ih.ss;
779
780 if (flag & MAXMEM)
781 { imagesize -= 2; oh.max = get_le16(ibuf+imagesize); }
782 if (flag & MINMEM)
783 { imagesize -= 2; oh.min = get_le16(ibuf+imagesize); }
784 if (flag & SP)
785 { imagesize -= 2; oh.sp = get_le16(ibuf+imagesize); }
786 if (flag & SS)
787 { imagesize -= 2; oh.ss = get_le16(ibuf+imagesize); }
788
789 unsigned ip = (flag & USEJUMP) ? get_le32(ibuf+imagesize-4) : (unsigned) ih.firstreloc;
790 oh.ip = ip & 0xffff;
791 oh.cs = ip >> 16;
792
793 oh.relocoffs = sizeof(oh);
794 oh.firstreloc = 0;
795 if (!fo)
796 return;
797
798 // write header + relocations + uncompressed file
799 fo->write(&oh,sizeof(oh));
800 if (relocn)
801 fo->write(wrkmem,relocn*4);
802 fo->write(obuf, ptr_diff(relocs, obuf));
803
804 // copy the overlay
805 copyOverlay(fo, ih_overlay, &obuf);
806 }
807
808
newLinker() const809 Linker* PackExe::newLinker() const
810 {
811 return new ElfLinkerX86();
812 }
813
814 /*
815
816 memory layout at decompression time
817 ===================================
818
819 normal exe
820 ----------
821
822 a, at load time
823
824 (e - copying code, C - compressed data, d - decompressor+relocator,
825 x - not specified, U - uncompressed code+data, R uncompressed relocation)
826
827 eeCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCdddd
828 ^ CS:0 ^ SS:0
829
830 b, after copying
831
832 xxxxxxxxxxxxxxxCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCdddd
833 ^ES:DI=0 ^ DS:SI=0 ^ CS=SS, IP in range 0..0xf
834
835 c, after uncompression
836
837 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUURRdddd
838 ^ ES:DI
839
840 device driver
841 -------------
842
843 the file has 2 entry points, CS:0 in device driver mode, and
844 CS:exe_as_device_entry in normal mode. the code in section DEVICEENTRY
845 sets up the same environment for section EXEENTRY, as it would see in normal
846 execution mode.
847
848 lzma uncompression for normal exes
849 ----------------------------------
850
851 (n - nrv2b uncompressor, l - nrv2b compressed lzma + relocator code)
852
853 a, at load time
854
855 nneelllCCCCCCCCCCCCCCCCCCCCCCCCC
856
857 ^ CS:0 ^ SS:0
858
859 b, after nrv2b
860
861 nneelllCCCCCCCCCCCCCCCCCCCCCCCCC dddd
862 ^ CS:0 ^ SS:0x10
863
864 after this, normal ee code runs
865
866 lzma + device driver
867 --------------------
868
869 (D - device driver adapter)
870
871 a, at load time
872
873 DDnneelllCCCCCCCCCCCCCCCCCCCCCCCCC
874
875 */
876
877 /* vim:set ts=4 sw=4 et: */
878