1 /* packer.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 "packer.h"
32 #include "filter.h"
33 #include "linker.h"
34 #include "ui.h"
35
36
37 /*************************************************************************
38 //
39 **************************************************************************/
40
Packer(InputFile * f)41 Packer::Packer(InputFile *f) :
42 bele(NULL),
43 fi(f), file_size(-1), ph_format(-1), ph_version(-1),
44 uip(NULL), linker(NULL),
45 last_patch(NULL), last_patch_len(0), last_patch_off(0)
46 {
47 if (fi != NULL)
48 file_size = fi->st_size();
49 uip = new UiPacker(this);
50 mem_clear(&ph, sizeof(ph));
51 }
52
53
~Packer()54 Packer::~Packer()
55 {
56 delete uip; uip = NULL;
57 delete linker; linker = NULL;
58 }
59
60
61 // for PackMaster
assertPacker() const62 void Packer::assertPacker() const
63 {
64 assert(getFormat() > 0);
65 assert(getFormat() < 255);
66 assert(getVersion() >= 11);
67 assert(getVersion() <= 14);
68 assert(strlen(getName()) <= 15);
69 // info: 36 is the limit for show_all_packers() in help.cpp
70 assert(strlen(getFullName(opt)) <= 32);
71 assert(strlen(getFullName(NULL)) <= 32);
72 if (bele == NULL) fprintf(stderr, "%s\n", getName());
73 assert(bele != NULL);
74 if (getFormat() != UPX_F_MACH_FAT) // macho/fat is multiarch
75 {
76 const N_BELE_RTP::AbstractPolicy *format_bele;
77 if (getFormat() < 128)
78 format_bele = &N_BELE_RTP::le_policy;
79 else
80 format_bele = &N_BELE_RTP::be_policy;
81 if (bele != format_bele) fprintf(stderr, "%s\n", getName());
82 assert(bele == format_bele);
83 }
84 #if 1
85 Linker *l = newLinker();
86 if (bele != l->bele) fprintf(stderr, "%s\n", getName());
87 assert(bele == l->bele);
88 delete l;
89 #endif
90 }
91
92
93 /*************************************************************************
94 // public entries called from class PackMaster
95 **************************************************************************/
96
doPack(OutputFile * fo)97 void Packer::doPack(OutputFile *fo)
98 {
99 uip->uiPackStart(fo);
100 pack(fo);
101 uip->uiPackEnd(fo);
102 }
103
doUnpack(OutputFile * fo)104 void Packer::doUnpack(OutputFile *fo)
105 {
106 uip->uiUnpackStart(fo);
107 unpack(fo);
108 uip->uiUnpackEnd(fo);
109 }
110
doTest()111 void Packer::doTest()
112 {
113 uip->uiTestStart();
114 test();
115 uip->uiTestEnd();
116 }
117
doList()118 void Packer::doList()
119 {
120 uip->uiListStart();
121 list();
122 uip->uiListEnd();
123 }
124
doFileInfo()125 void Packer::doFileInfo()
126 {
127 uip->uiFileInfoStart();
128 fileInfo();
129 uip->uiFileInfoEnd();
130 }
131
132
133 /*************************************************************************
134 // default actions
135 **************************************************************************/
136
test()137 void Packer::test()
138 {
139 unpack(NULL);
140 }
141
142
list()143 void Packer::list()
144 {
145 uip->uiList();
146 }
147
148
fileInfo()149 void Packer::fileInfo()
150 {
151 // FIXME: subclasses should list their sections here
152 // We also should try to get a nice layout...
153 }
154
155
testUnpackVersion(int version) const156 bool Packer::testUnpackVersion(int version) const
157 {
158 if (version != ph_version && ph_version != -1)
159 throwCantUnpack("program has been modified; run a virus checker!");
160 if (!canUnpackVersion(version))
161 throwCantUnpack("I am not compatible with older versions of UPX");
162 return true;
163 }
164
165
testUnpackFormat(int format) const166 bool Packer::testUnpackFormat(int format) const
167 {
168 if (format != ph_format && ph_format != -1)
169 throwCantUnpack("program has been modified; run a virus checker!");
170 return canUnpackFormat(format);
171 }
172
173
ph_skipVerify(const PackHeader & ph)174 bool ph_skipVerify(const PackHeader &ph)
175 {
176 if (M_IS_DEFLATE(ph.method))
177 return false;
178 if (M_IS_LZMA(ph.method))
179 return false;
180 if (ph.level > 1)
181 return false;
182 return true;
183 }
184
185
186 /*************************************************************************
187 // compress - wrap call to low-level upx_compress()
188 **************************************************************************/
189
compress(upx_bytep i_ptr,unsigned i_len,upx_bytep o_ptr,const upx_compress_config_t * cconf_parm)190 bool Packer::compress(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr,
191 const upx_compress_config_t *cconf_parm)
192 {
193 ph.u_len = i_len;
194 ph.c_len = 0;
195 assert(ph.level >= 1); assert(ph.level <= 10);
196
197 // Avoid too many progress bar updates. 64 is s->bar_len in ui.cpp.
198 unsigned step = (ph.u_len < 64*1024) ? 0 : ph.u_len / 64;
199
200 // save current checksums
201 ph.saved_u_adler = ph.u_adler;
202 ph.saved_c_adler = ph.c_adler;
203 // update checksum of uncompressed data
204 ph.u_adler = upx_adler32(i_ptr, ph.u_len, ph.u_adler);
205
206 // set compression parameters
207 upx_compress_config_t cconf; cconf.reset();
208 if (cconf_parm)
209 cconf = *cconf_parm;
210 // cconf options
211 if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
212 {
213 if (opt->crp.crp_ucl.c_flags != -1)
214 cconf.conf_ucl.c_flags = opt->crp.crp_ucl.c_flags;
215 if (opt->crp.crp_ucl.p_level != -1)
216 cconf.conf_ucl.p_level = opt->crp.crp_ucl.p_level;
217 if (opt->crp.crp_ucl.h_level != -1)
218 cconf.conf_ucl.h_level = opt->crp.crp_ucl.h_level;
219 if (opt->crp.crp_ucl.max_offset != UINT_MAX && opt->crp.crp_ucl.max_offset < cconf.conf_ucl.max_offset)
220 cconf.conf_ucl.max_offset = opt->crp.crp_ucl.max_offset;
221 if (opt->crp.crp_ucl.max_match != UINT_MAX && opt->crp.crp_ucl.max_match < cconf.conf_ucl.max_match)
222 cconf.conf_ucl.max_match = opt->crp.crp_ucl.max_match;
223 #if (WITH_NRV)
224 if (ph.level >= 7 || (ph.level >= 4 && ph.u_len >= 512*1024))
225 step = 0;
226 #endif
227 }
228 if (M_IS_LZMA(ph.method))
229 {
230 oassign(cconf.conf_lzma.pos_bits, opt->crp.crp_lzma.pos_bits);
231 oassign(cconf.conf_lzma.lit_pos_bits, opt->crp.crp_lzma.lit_pos_bits);
232 oassign(cconf.conf_lzma.lit_context_bits, opt->crp.crp_lzma.lit_context_bits);
233 oassign(cconf.conf_lzma.dict_size, opt->crp.crp_lzma.dict_size);
234 oassign(cconf.conf_lzma.num_fast_bytes, opt->crp.crp_lzma.num_fast_bytes);
235 }
236 if (M_IS_DEFLATE(ph.method))
237 {
238 oassign(cconf.conf_zlib.mem_level, opt->crp.crp_zlib.mem_level);
239 oassign(cconf.conf_zlib.window_bits, opt->crp.crp_zlib.window_bits);
240 oassign(cconf.conf_zlib.strategy, opt->crp.crp_zlib.strategy);
241 }
242 if (uip->ui_pass >= 0)
243 uip->ui_pass++;
244 uip->startCallback(ph.u_len, step, uip->ui_pass, uip->ui_total_passes);
245 uip->firstCallback();
246
247 //OutputFile::dump("data.raw", in, ph.u_len);
248
249 // compress
250 int r = upx_compress(i_ptr, ph.u_len, o_ptr, &ph.c_len,
251 uip->getCallback(),
252 ph.method, ph.level, &cconf, &ph.compress_result);
253
254 //uip->finalCallback(ph.u_len, ph.c_len);
255 uip->endCallback();
256
257 if (r == UPX_E_OUT_OF_MEMORY)
258 throwOutOfMemoryException();
259 if (r != UPX_E_OK)
260 throwInternalError("compression failed");
261
262 if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
263 {
264 const ucl_uint *res = ph.compress_result.result_ucl.result;
265 //ph.min_offset_found = res[0];
266 ph.max_offset_found = res[1];
267 //ph.min_match_found = res[2];
268 ph.max_match_found = res[3];
269 //ph.min_run_found = res[4];
270 ph.max_run_found = res[5];
271 ph.first_offset_found = res[6];
272 //ph.same_match_offsets_found = res[7];
273 if (cconf_parm)
274 {
275 assert(cconf.conf_ucl.max_offset == 0 || cconf.conf_ucl.max_offset >= ph.max_offset_found);
276 assert(cconf.conf_ucl.max_match == 0 || cconf.conf_ucl.max_match >= ph.max_match_found);
277 }
278 }
279
280 //printf("\nPacker::compress: %d/%d: %7d -> %7d\n", ph.method, ph.level, ph.u_len, ph.c_len);
281 if (!checkCompressionRatio(ph.u_len, ph.c_len))
282 return false;
283 // return in any case if not compressible
284 if (ph.c_len >= ph.u_len)
285 return false;
286
287 // update checksum of compressed data
288 ph.c_adler = upx_adler32(o_ptr, ph.c_len, ph.c_adler);
289 // Decompress and verify. Skip this when using the fastest level.
290 if (!ph_skipVerify(ph))
291 {
292 // decompress
293 unsigned new_len = ph.u_len;
294 r = upx_decompress(o_ptr, ph.c_len, i_ptr, &new_len, ph.method, &ph.compress_result);
295 if (r == UPX_E_OUT_OF_MEMORY)
296 throwOutOfMemoryException();
297 //printf("%d %d: %d %d %d\n", ph.method, r, ph.c_len, ph.u_len, new_len);
298 if (r != UPX_E_OK)
299 throwInternalError("decompression failed");
300 if (new_len != ph.u_len)
301 throwInternalError("decompression failed (size error)");
302
303 // verify decompression
304 if (ph.u_adler != upx_adler32(i_ptr, ph.u_len, ph.saved_u_adler))
305 throwInternalError("decompression failed (checksum error)");
306 }
307 return true;
308 }
309
310
311 #if 0
312 bool Packer::compress(upx_bytep in, upx_bytep out,
313 const upx_compress_config_t *cconf)
314 {
315 return ph_compress(ph, in, out, cconf);
316 }
317 #endif
318
319
checkDefaultCompressionRatio(unsigned u_len,unsigned c_len) const320 bool Packer::checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const
321 {
322 assert((int)u_len > 0);
323 assert((int)c_len > 0);
324 if (c_len >= u_len)
325 return false;
326 unsigned gain = u_len - c_len;
327
328 if (gain < 512) // need at least 512 bytes gain
329 return false;
330 #if 1
331 if (gain >= 4096) // ok if we have 4096 bytes gain
332 return true;
333 if (gain >= u_len / 16) // ok if we have 6.25% gain
334 return true;
335 return false;
336 #else
337 return true;
338 #endif
339 }
340
341
checkCompressionRatio(unsigned u_len,unsigned c_len) const342 bool Packer::checkCompressionRatio(unsigned u_len, unsigned c_len) const
343 {
344 return checkDefaultCompressionRatio(u_len, c_len);
345 }
346
checkFinalCompressionRatio(const OutputFile * fo) const347 bool Packer::checkFinalCompressionRatio(const OutputFile *fo) const
348 {
349 const unsigned u_len = file_size;
350 const unsigned c_len = fo->getBytesWritten();
351 return checkDefaultCompressionRatio(u_len, c_len);
352 }
353
354
355 /*************************************************************************
356 // decompress
357 **************************************************************************/
358
ph_decompress(PackHeader & ph,const upx_bytep in,upx_bytep out,bool verify_checksum,Filter * ft)359 void ph_decompress(PackHeader &ph, const upx_bytep in, upx_bytep out,
360 bool verify_checksum, Filter *ft)
361 {
362 unsigned adler;
363
364 // verify checksum of compressed data
365 if (verify_checksum)
366 {
367 adler = upx_adler32(in, ph.c_len, ph.saved_c_adler);
368 if (adler != ph.c_adler)
369 throwChecksumError();
370 }
371
372 // decompress
373 if (ph.u_len < ph.c_len) {
374 throwCantUnpack("header corrupted");
375 }
376 unsigned new_len = ph.u_len;
377 int r = upx_decompress(in, ph.c_len, out, &new_len, ph.method, &ph.compress_result);
378 if (r == UPX_E_OUT_OF_MEMORY)
379 throwOutOfMemoryException();
380 if (r != UPX_E_OK || new_len != ph.u_len)
381 throwCompressedDataViolation();
382
383 // verify checksum of decompressed data
384 if (verify_checksum)
385 {
386 if (ft)
387 ft->unfilter(out, ph.u_len);
388 adler = upx_adler32(out, ph.u_len, ph.saved_u_adler);
389 if (adler != ph.u_adler)
390 throwChecksumError();
391 }
392 }
393
394
decompress(const upx_bytep in,upx_bytep out,bool verify_checksum,Filter * ft)395 void Packer::decompress(const upx_bytep in, upx_bytep out,
396 bool verify_checksum, Filter *ft)
397 {
398 ph_decompress(ph, in, out, verify_checksum, ft);
399 }
400
401
402 /*************************************************************************
403 // overlapping decompression
404 **************************************************************************/
405
406 static
ph_testOverlappingDecompression(const PackHeader & ph,const upx_bytep buf,const upx_bytep tbuf,unsigned overlap_overhead)407 bool ph_testOverlappingDecompression(const PackHeader &ph,
408 const upx_bytep buf,
409 const upx_bytep tbuf,
410 unsigned overlap_overhead)
411 {
412 if (ph.c_len >= ph.u_len)
413 return false;
414
415 assert((int) overlap_overhead >= 0);
416 assert((int) (ph.u_len + overlap_overhead) >= 0);
417
418 // Because upx_test_overlap() does not use the asm_fast decompressor
419 // we must account for extra 3 bytes that asm_fast does use,
420 // or else we may fail at runtime decompression.
421 unsigned extra = 0;
422 if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
423 extra = 3;
424 if (overlap_overhead <= 4 + extra) // don't waste time here
425 return false;
426 overlap_overhead -= extra;
427
428 unsigned src_off = ph.u_len + overlap_overhead - ph.c_len;
429 unsigned new_len = ph.u_len;
430 int r = upx_test_overlap(buf - src_off, tbuf,
431 src_off, ph.c_len, &new_len,
432 ph.method, &ph.compress_result);
433 if (r == UPX_E_OUT_OF_MEMORY)
434 throwOutOfMemoryException();
435 return (r == UPX_E_OK && new_len == ph.u_len);
436 }
437
438
testOverlappingDecompression(const upx_bytep buf,const upx_bytep tbuf,unsigned overlap_overhead) const439 bool Packer::testOverlappingDecompression(const upx_bytep buf, const upx_bytep tbuf,
440 unsigned overlap_overhead) const
441 {
442 return ph_testOverlappingDecompression(ph, buf, tbuf, overlap_overhead);
443 }
444
445
verifyOverlappingDecompression(Filter * ft)446 void Packer::verifyOverlappingDecompression(Filter *ft)
447 {
448 assert(ph.c_len < ph.u_len);
449 assert((int)ph.overlap_overhead > 0);
450 // Idea:
451 // obuf[] was allocated with MemBuffer::allocForCompression(), and
452 // its contents are no longer needed, i.e. the compressed data
453 // must have been already written.
454 // We now can perform a real overlapping decompression and
455 // verify the checksum.
456 //
457 // Note:
458 // This verify is just because of complete paranoia that there
459 // could be a hidden bug in the upx_test_overlap implementation,
460 // and it should not be necessary at all.
461 //
462 // See also:
463 // Filter::verifyUnfilter()
464
465 if (ph_skipVerify(ph))
466 return;
467 unsigned offset = (ph.u_len + ph.overlap_overhead) - ph.c_len;
468 if (offset + ph.c_len > obuf.getSize())
469 return;
470 memmove(obuf + offset, obuf, ph.c_len);
471 decompress(obuf + offset, obuf, true, ft);
472 obuf.checkState();
473 }
474
475
verifyOverlappingDecompression(upx_bytep o_ptr,unsigned o_size,Filter * ft)476 void Packer::verifyOverlappingDecompression(upx_bytep o_ptr, unsigned o_size, Filter *ft)
477 {
478 assert(ph.c_len < ph.u_len);
479 assert((int)ph.overlap_overhead > 0);
480 if (ph_skipVerify(ph))
481 return;
482 unsigned offset = (ph.u_len + ph.overlap_overhead) - ph.c_len;
483 if (offset + ph.c_len > o_size)
484 return;
485 memmove(o_ptr + offset, o_ptr, ph.c_len);
486 decompress(o_ptr + offset, o_ptr, true, ft);
487 }
488
489
490 /*************************************************************************
491 // Find overhead for in-place decompression in a heuristic way
492 // (using a binary search). Return 0 on error.
493 //
494 // To speed up things:
495 // - you can pass the range of an acceptable interval (so that
496 // we can succeed early)
497 // - you can enforce an upper_limit (so that we can fail early)
498 **************************************************************************/
499
findOverlapOverhead(const upx_bytep buf,const upx_bytep tbuf,unsigned range,unsigned upper_limit) const500 unsigned Packer::findOverlapOverhead(const upx_bytep buf,
501 const upx_bytep tbuf,
502 unsigned range,
503 unsigned upper_limit) const
504 {
505 assert((int) range >= 0);
506
507 // prepare to deal with very pessimistic values
508 unsigned low = 1;
509 unsigned high = UPX_MIN(ph.u_len + 512, upper_limit);
510 // but be optimistic for first try (speedup)
511 unsigned m = UPX_MIN(16u, high);
512 //
513 unsigned overhead = 0;
514 unsigned nr = 0; // statistics
515
516 while (high >= low)
517 {
518 assert(m >= low); assert(m <= high);
519 assert(m < overhead || overhead == 0);
520 nr++;
521 bool success = testOverlappingDecompression(buf, tbuf, m);
522 //printf("testOverlapOverhead(%d): %d %d: %d -> %d\n", nr, low, high, m, (int)success);
523 if (success)
524 {
525 overhead = m;
526 // Succeed early if m lies in [low .. low+range-1], i.e. if
527 // if the range of the current interval is <= range.
528 // if (m <= low + range - 1)
529 // if (m < low + range)
530 if (m - low < range) // avoid underflow
531 break;
532 high = m - 1;
533 }
534 else
535 low = m + 1;
536 ////m = (low + high) / 2;
537 m = (low & high) + ((low ^ high) >> 1); // avoid overflow
538 }
539
540 //printf("findOverlapOverhead: %d (%d tries)\n", overhead, nr);
541 if (overhead == 0)
542 throwInternalError("this is an oo bug");
543
544 UNUSED(nr);
545 return overhead;
546 }
547
548
549 /*************************************************************************
550 // file i/o utils
551 **************************************************************************/
552
handleStub(InputFile * fif,OutputFile * fo,unsigned size)553 void Packer::handleStub(InputFile *fif, OutputFile *fo, unsigned size)
554 {
555 if (fo)
556 {
557 if (size > 0)
558 {
559 // copy stub from exe
560 info("Copying original stub: %u bytes", size);
561 ByteArray(stub, size);
562 fif->seek(0,SEEK_SET);
563 fif->readx(stub,size);
564 fo->write(stub,size);
565 }
566 else
567 {
568 // no stub
569 }
570 }
571 }
572
573
checkOverlay(unsigned overlay)574 void Packer::checkOverlay(unsigned overlay)
575 {
576 if ((int)overlay < 0 || (off_t)overlay > file_size)
577 throw OverlayException("invalid overlay size; file is possibly corrupt");
578 if (overlay == 0)
579 return;
580 info("Found overlay: %d bytes", overlay);
581 if (opt->overlay == opt->SKIP_OVERLAY)
582 throw OverlayException("file has overlay -- skipped; try '--overlay=copy'");
583 }
584
585
copyOverlay(OutputFile * fo,unsigned overlay,MemBuffer * buf,bool do_seek)586 void Packer::copyOverlay(OutputFile *fo, unsigned overlay,
587 MemBuffer *buf,
588 bool do_seek)
589 {
590 assert((int)overlay >= 0);
591 assert((off_t)overlay < file_size);
592 buf->checkState();
593 if (!fo || overlay == 0)
594 return;
595 if (opt->overlay != opt->COPY_OVERLAY)
596 {
597 assert(opt->overlay == opt->STRIP_OVERLAY);
598 infoWarning("stripping overlay: %d bytes", overlay);
599 return;
600 }
601 info("Copying overlay: %d bytes", overlay);
602 if (do_seek)
603 fi->seek(-(off_t)overlay, SEEK_END);
604
605 // get buffer size, align to improve i/o speed
606 unsigned buf_size = buf->getSize();
607 if (buf_size > 65536)
608 buf_size = ALIGN_DOWN(buf_size, 4096u);
609 assert((int)buf_size > 0);
610
611 do {
612 unsigned len = overlay < buf_size ? overlay : buf_size;
613 fi->readx(buf, len);
614 fo->write(buf, len);
615 overlay -= len;
616 } while (overlay > 0);
617 buf->checkState();
618 }
619
620
621 // Create a pseudo-unique program id.
getRandomId() const622 unsigned Packer::getRandomId() const
623 {
624 if (opt->debug.disable_random_id)
625 return 0x01020304;
626 unsigned id = 0;
627 #if 0 && defined(__unix__)
628 // Don't consume precious bytes from /dev/urandom.
629 int fd = open("/dev/urandom", O_RDONLY | O_BINARY);
630 if (fd < 0)
631 fd = open("/dev/random", O_RDONLY | O_BINARY);
632 if (fd >= 0)
633 {
634 if (read(fd, &id, 4) != 4)
635 id = 0;
636 close(fd);
637 }
638 #endif
639 while (id == 0)
640 {
641 #if !(HAVE_GETTIMEOFDAY) || ((ACC_OS_DOS32) && defined(__DJGPP__))
642 id ^= (unsigned) time(NULL);
643 id ^= ((unsigned) clock()) << 12;
644 #else
645 struct timeval tv;
646 gettimeofday(&tv, 0);
647 id ^= (unsigned) tv.tv_sec;
648 id ^= ((unsigned) tv.tv_usec) << 12; // shift into high-bits
649 #endif
650 #if (HAVE_GETPID)
651 id ^= (unsigned) getpid();
652 #endif
653 id ^= (unsigned) fi->st.st_ino;
654 id ^= (unsigned) fi->st.st_atime;
655 id ^= (unsigned) rand();
656 }
657 return id;
658 }
659
660
661 /*************************************************************************
662 // packheader util
663 **************************************************************************/
664
665 // this is called directly after the constructor from class PackMaster
initPackHeader()666 void Packer::initPackHeader()
667 {
668 mem_clear(&ph, sizeof(ph));
669 ph.version = getVersion();
670 ph.format = getFormat();
671 ph.method = M_NONE;
672 ph.level = -1;
673 ph.u_adler = ph.c_adler = ph.saved_u_adler = ph.saved_c_adler = upx_adler32(NULL,0);
674 ph.buf_offset = 0;
675 ph.u_file_size = file_size;
676 }
677
678
679 // this is called directly after canPack() from class PackMaster
updatePackHeader()680 void Packer::updatePackHeader()
681 {
682 assert(opt->cmd == CMD_COMPRESS);
683 //
684 const int *m = getCompressionMethods(opt->method, opt->level);
685 ph.method = m[0];
686 ph.level = opt->level;
687 if (ph.level < 0)
688 ph.level = file_size < 512*1024 ? 8 : 7;
689 //
690 assert(isValidCompressionMethod(ph.method));
691 assert(1 <= ph.level && ph.level <= 10);
692 }
693
694
695 // FIXME: remove patchPackHeader() and fold into relocateLoader();
696 // then make linker->relocate() private (friend Packer)
patchPackHeader(void * b,int blen)697 int Packer::patchPackHeader(void *b, int blen)
698 {
699 assert(isValidFilter(ph.filter));
700
701 const int size = ph.getPackHeaderSize();
702 if (linker->findSection("UPX1HEAD", false))
703 assert(size == linker->getSectionSize("UPX1HEAD"));
704 int boff = find_le32(b, blen, UPX_MAGIC_LE32);
705 checkPatch(b, blen, boff, size);
706
707 unsigned char *p = (unsigned char *)b + boff;
708 ph.putPackHeader(p);
709
710 return boff;
711 }
712
713
getPackHeader(void * b,int blen,bool allow_incompressible)714 bool Packer::getPackHeader(void *b, int blen, bool allow_incompressible)
715 {
716 if (!ph.fillPackHeader((unsigned char *)b, blen))
717 return false;
718
719 if (ph.version > getVersion())
720 throwCantUnpack("need a newer version of UPX");
721 // Some formats might be able to unpack old versions because
722 // their implementation hasn't changed. Ask them.
723 if (opt->cmd != CMD_FILEINFO)
724 if (!testUnpackVersion(ph.version))
725 return false;
726
727 if (ph.c_len > ph.u_len
728 || (ph.c_len == ph.u_len && !allow_incompressible)
729 || (off_t)ph.c_len >= file_size
730 || ph.version <= 0 || ph.version >= 0xff)
731 throwCantUnpack("header corrupted");
732 else if ((off_t)ph.u_len > ph.u_file_size)
733 {
734 #if 0
735 // FIXME: does this check make sense w.r.t. overlays ???
736 if (ph.format == UPX_F_WIN32_PE || ph.format == UPX_F_DOS_EXE)
737 // may get longer
738 ((void)0);
739 else
740 throwCantUnpack("header size corrupted");
741 #endif
742 }
743 if (!isValidCompressionMethod(ph.method))
744 throwCantUnpack("unknown compression method (try a newer version of UPX)");
745
746 // Some formats might be able to unpack "subformats". Ask them.
747 if (!testUnpackFormat(ph.format))
748 return false;
749
750 return true;
751 }
752
753
readPackHeader(int len,bool allow_incompressible)754 bool Packer::readPackHeader(int len, bool allow_incompressible)
755 {
756 assert((int)len > 0);
757 MemBuffer buf(len);
758 len = fi->read(buf, len);
759 if (len <= 0)
760 return false;
761 return getPackHeader(buf, len, allow_incompressible);
762 }
763
764
checkAlreadyPacked(const void * b,int blen)765 void Packer::checkAlreadyPacked(const void *b, int blen)
766 {
767 int boff = find_le32(b, blen, UPX_MAGIC_LE32);
768 if (boff < 0)
769 return;
770
771 // FIXME: could add some more checks to verify that this
772 // is a real PackHeader, e.g.
773 //
774 //PackHeader tmp;
775 //if (!tmp.fillPackHeader((unsigned char *)b + boff, blen - boff))
776 // return;
777 //
778 // This also would require that the buffer in 'b' holds
779 // the full PackHeader, and not only the 4 magic bytes.
780
781 throwAlreadyPacked();
782 }
783
784
785 /*************************************************************************
786 // patch util for loader
787 **************************************************************************/
788
checkPatch(void * b,int blen,int boff,int size)789 void Packer::checkPatch(void *b, int blen, int boff, int size)
790 {
791 if (b == NULL && blen == 0 && boff == 0 && size == 0)
792 {
793 // reset
794 last_patch = NULL;
795 last_patch_len = 0;
796 last_patch_off = 0;
797 return;
798 }
799 if (b == NULL || blen <= 0 || boff < 0 || size <= 0)
800 throwBadLoader();
801 if (boff + size <= 0 || boff + size > blen)
802 throwBadLoader();
803 //printf("checkPatch: %p %5d %5d %2d\n", b, blen, boff, size);
804 if (b == last_patch)
805 {
806 if (boff + size > last_patch_off)
807 throwInternalError("invalid patch order");
808 // The next check is not strictly necessary, but the buffer
809 // length should better not increase...
810 if (blen > last_patch_len)
811 throwInternalError("invalid patch order (length)");
812 }
813 else
814 last_patch = b;
815 last_patch_len = blen;
816 last_patch_off = boff;
817 }
818
819
patch_be16(void * b,int blen,unsigned old,unsigned new_)820 int Packer::patch_be16(void *b, int blen, unsigned old, unsigned new_)
821 {
822 int boff = find_be16(b, blen, old);
823 checkPatch(b, blen, boff, 2);
824
825 unsigned char *p = (unsigned char *)b + boff;
826 set_be16(p, new_);
827
828 return boff;
829 }
830
831
patch_be16(void * b,int blen,const void * old,unsigned new_)832 int Packer::patch_be16(void *b, int blen, const void *old, unsigned new_)
833 {
834 int boff = find(b, blen, old, 2);
835 checkPatch(b, blen, boff, 2);
836
837 unsigned char *p = (unsigned char *)b + boff;
838 set_be16(p, new_);
839
840 return boff;
841 }
842
843
patch_be32(void * b,int blen,unsigned old,unsigned new_)844 int Packer::patch_be32(void *b, int blen, unsigned old, unsigned new_)
845 {
846 int boff = find_be32(b, blen, old);
847 checkPatch(b, blen, boff, 4);
848
849 unsigned char *p = (unsigned char *)b + boff;
850 set_be32(p, new_);
851
852 return boff;
853 }
854
855
patch_be32(void * b,int blen,const void * old,unsigned new_)856 int Packer::patch_be32(void *b, int blen, const void *old, unsigned new_)
857 {
858 int boff = find(b, blen, old, 4);
859 checkPatch(b, blen, boff, 4);
860
861 unsigned char *p = (unsigned char *)b + boff;
862 set_be32(p, new_);
863
864 return boff;
865 }
866
867
patch_le16(void * b,int blen,unsigned old,unsigned new_)868 int Packer::patch_le16(void *b, int blen, unsigned old, unsigned new_)
869 {
870 int boff = find_le16(b, blen, old);
871 checkPatch(b, blen, boff, 2);
872
873 unsigned char *p = (unsigned char *)b + boff;
874 set_le16(p, new_);
875
876 return boff;
877 }
878
879
patch_le16(void * b,int blen,const void * old,unsigned new_)880 int Packer::patch_le16(void *b, int blen, const void *old, unsigned new_)
881 {
882 int boff = find(b, blen, old, 2);
883 checkPatch(b, blen, boff, 2);
884
885 unsigned char *p = (unsigned char *)b + boff;
886 set_le16(p, new_);
887
888 return boff;
889 }
890
891
patch_le32(void * b,int blen,unsigned old,unsigned new_)892 int Packer::patch_le32(void *b, int blen, unsigned old, unsigned new_)
893 {
894 int boff = find_le32(b, blen, old);
895 checkPatch(b, blen, boff, 4);
896
897 unsigned char *p = (unsigned char *)b + boff;
898 set_le32(p, new_);
899
900 return boff;
901 }
902
903
patch_le32(void * b,int blen,const void * old,unsigned new_)904 int Packer::patch_le32(void *b, int blen, const void *old, unsigned new_)
905 {
906 int boff = find(b, blen, old, 4);
907 checkPatch(b, blen, boff, 4);
908
909 unsigned char *p = (unsigned char *)b + boff;
910 set_le32(p, new_);
911
912 return boff;
913 }
914
915
916 /*************************************************************************
917 // relocation util
918 **************************************************************************/
919
optimizeReloc(upx_byte * in,unsigned relocnum,upx_byte * out,upx_byte * image,int bswap,int * big,int bits)920 upx_byte *Packer::optimizeReloc(upx_byte *in, unsigned relocnum,
921 upx_byte *out, upx_byte *image,
922 int bswap, int *big, int bits)
923 {
924 if (opt->exact)
925 throwCantPackExact();
926
927 *big = 0;
928 if (relocnum == 0)
929 return out;
930 qsort(in,relocnum,4,le32_compare);
931
932 unsigned jc,pc,oc;
933 upx_byte *fix = out;
934
935 pc = (unsigned) -4;
936 for (jc = 0; jc<relocnum; jc++)
937 {
938 oc = get_le32(in+jc*4) - pc;
939 if (oc == 0)
940 continue;
941 else if ((int)oc < 4)
942 throwCantPack("overlapping fixups");
943 else if (oc < 0xF0)
944 *fix++ = (unsigned char) oc;
945 else if (oc < 0x100000)
946 {
947 *fix++ = (unsigned char) (0xF0+(oc>>16));
948 *fix++ = (unsigned char) oc;
949 *fix++ = (unsigned char) (oc>>8);
950 }
951 else
952 {
953 *big = 1;
954 *fix++ = 0xf0;
955 *fix++ = 0;
956 *fix++ = 0;
957 set_le32(fix,oc);
958 fix += 4;
959 }
960 pc += oc;
961 if (bswap)
962 {
963 if (bits == 32)
964 acc_ua_swab32s(image + pc);
965 else if (bits == 64)
966 set_be64(image + pc, get_le64(image + pc));
967 else
968 throwInternalError("optimizeReloc problem");
969 }
970 }
971 *fix++ = 0;
972 return fix;
973 }
974
optimizeReloc32(upx_byte * in,unsigned relocnum,upx_byte * out,upx_byte * image,int bswap,int * big)975 upx_byte *Packer::optimizeReloc32(upx_byte *in, unsigned relocnum,
976 upx_byte *out, upx_byte *image,
977 int bswap, int *big)
978 {
979 return optimizeReloc(in, relocnum, out, image, bswap, big, 32);
980 }
981
optimizeReloc64(upx_byte * in,unsigned relocnum,upx_byte * out,upx_byte * image,int bswap,int * big)982 upx_byte *Packer::optimizeReloc64(upx_byte *in, unsigned relocnum,
983 upx_byte *out, upx_byte *image,
984 int bswap, int *big)
985 {
986 return optimizeReloc(in, relocnum, out, image, bswap, big, 64);
987 }
988
989
unoptimizeReloc(upx_byte ** in,upx_byte * image,MemBuffer * out,int bswap,int bits)990 unsigned Packer::unoptimizeReloc(upx_byte **in, upx_byte *image,
991 MemBuffer *out, int bswap, int bits)
992 {
993 upx_byte *p;
994 unsigned relocn = 0;
995 for (p = *in; *p; p++, relocn++)
996 if (*p >= 0xF0)
997 {
998 if (*p == 0xF0 && get_le16(p+1) == 0)
999 p += 4;
1000 p += 2;
1001 }
1002 //fprintf(stderr,"relocnum=%x\n",relocn);
1003 out->alloc(4*relocn+4); // one extra data
1004 LE32 *outp = (LE32*) (unsigned char *) *out;
1005 LE32 *relocs = outp;
1006 unsigned jc = (unsigned) -4;
1007 for (p = *in; *p; p++)
1008 {
1009 if (*p < 0xF0)
1010 jc += *p;
1011 else
1012 {
1013 unsigned dif = (*p & 0x0F)*0x10000 + get_le16(p+1);
1014 p += 2;
1015 if (dif == 0)
1016 {
1017 dif = get_le32(p+1);
1018 p += 4;
1019 }
1020 jc += dif;
1021 }
1022 *relocs++ = jc;
1023 if (bswap && image)
1024 {
1025 if (bits == 32)
1026 acc_ua_swab32s(image + jc);
1027 else if (bits == 64)
1028 set_be64(image + jc, get_le64(image + jc));
1029 else
1030 throwInternalError("unoptimizeReloc problem");
1031 }
1032 }
1033 //fprintf(stderr,"relocnum=%x\n",relocn);
1034 *in = p+1;
1035 return (unsigned) (relocs - outp);
1036 }
1037
unoptimizeReloc32(upx_byte ** in,upx_byte * image,MemBuffer * out,int bswap)1038 unsigned Packer::unoptimizeReloc32(upx_byte **in, upx_byte *image,
1039 MemBuffer *out, int bswap)
1040 {
1041 return unoptimizeReloc(in, image, out, bswap, 32);
1042 }
1043
unoptimizeReloc64(upx_byte ** in,upx_byte * image,MemBuffer * out,int bswap)1044 unsigned Packer::unoptimizeReloc64(upx_byte **in, upx_byte *image,
1045 MemBuffer *out, int bswap)
1046 {
1047 return unoptimizeReloc(in, image, out, bswap, 64);
1048 }
1049
1050 /*************************************************************************
1051 // loader util (interface to linker)
1052 **************************************************************************/
1053
getIdentstr(unsigned * size,int small)1054 static const char *getIdentstr(unsigned *size, int small)
1055 {
1056 // IMPORTANT: we do NOT change "http://upx.sf.net"
1057 static char identbig[] =
1058 "\n\0"
1059 "$Info: "
1060 "This file is packed with the UPX executable packer http://upx.sf.net $"
1061 "\n\0"
1062 "$Id: UPX "
1063 UPX_VERSION_STRING4
1064 " Copyright (C) 1996-" UPX_VERSION_YEAR " the UPX Team. All Rights Reserved. $"
1065 "\n";
1066 static char identsmall[] =
1067 "\n"
1068 "$Id: UPX "
1069 "(C) 1996-" UPX_VERSION_YEAR " the UPX Team. All Rights Reserved. http://upx.sf.net $"
1070 "\n";
1071 static char identtiny[] = UPX_VERSION_STRING4;
1072
1073 static int done;
1074 if (!done && (opt->debug.fake_stub_version[0] || opt->debug.fake_stub_year[0]))
1075 {
1076 struct strinfo_t { char *s; int size; };
1077 static const strinfo_t strlist[] = {
1078 { identbig, (int)sizeof(identbig) },
1079 { identsmall, (int)sizeof(identsmall) },
1080 { identtiny, (int)sizeof(identtiny) },
1081 { NULL, 0 } };
1082 const strinfo_t* iter;
1083
1084 for (iter = strlist; iter->s; ++iter)
1085 {
1086 if (opt->debug.fake_stub_version[0])
1087 mem_replace(iter->s, iter->size, UPX_VERSION_STRING4, 4, opt->debug.fake_stub_version);
1088 if (opt->debug.fake_stub_year[0])
1089 mem_replace(iter->s, iter->size, UPX_VERSION_YEAR, 4, opt->debug.fake_stub_year);
1090 }
1091 done = 1;
1092 }
1093
1094
1095 if (small < 0)
1096 small = opt->small;
1097 if (small >= 2)
1098 {
1099 *size = sizeof(identtiny);
1100 return identtiny;
1101 }
1102 else if (small >= 1)
1103 {
1104 *size = sizeof(identsmall);
1105 return identsmall;
1106 }
1107 else
1108 {
1109 *size = sizeof(identbig);
1110 return identbig;
1111 }
1112 }
1113
1114
initLoader(const void * pdata,int plen,int small)1115 void Packer::initLoader(const void *pdata, int plen, int small)
1116 {
1117 delete linker;
1118 linker = newLinker();
1119 assert(bele == linker->bele);
1120 linker->init(pdata, plen);
1121
1122 unsigned size;
1123 char const * const ident = getIdentstr(&size, small);
1124 linker->addSection("IDENTSTR", ident, size, 0);
1125 }
1126
1127
1128 #define C const char *
1129 #define N ACC_STATIC_CAST(void *, 0)
addLoader(C a)1130 void Packer::addLoader(C a)
1131 { addLoaderVA(a, N); }
addLoader(C a,C b)1132 void Packer::addLoader(C a, C b)
1133 { addLoaderVA(a, b, N); }
addLoader(C a,C b,C c)1134 void Packer::addLoader(C a, C b, C c)
1135 { addLoaderVA(a, b, c, N); }
addLoader(C a,C b,C c,C d)1136 void Packer::addLoader(C a, C b, C c, C d)
1137 { addLoaderVA(a, b, c, d, N); }
addLoader(C a,C b,C c,C d,C e)1138 void Packer::addLoader(C a, C b, C c, C d, C e)
1139 { addLoaderVA(a, b, c, d, e, N); }
addLoader(C a,C b,C c,C d,C e,C f)1140 void Packer::addLoader(C a, C b, C c, C d, C e, C f)
1141 { addLoaderVA(a, b, c, d, e, f, N); }
addLoader(C a,C b,C c,C d,C e,C f,C g)1142 void Packer::addLoader(C a, C b, C c, C d, C e, C f, C g)
1143 { addLoaderVA(a, b, c, d, e, f, g, N); }
addLoader(C a,C b,C c,C d,C e,C f,C g,C h)1144 void Packer::addLoader(C a, C b, C c, C d, C e, C f, C g, C h)
1145 { addLoaderVA(a, b, c, d, e, f, g, h, N); }
addLoader(C a,C b,C c,C d,C e,C f,C g,C h,C i)1146 void Packer::addLoader(C a, C b, C c, C d, C e, C f, C g, C h, C i)
1147 { addLoaderVA(a, b, c, d, e, f, g, h, i, N); }
addLoader(C a,C b,C c,C d,C e,C f,C g,C h,C i,C j)1148 void Packer::addLoader(C a, C b, C c, C d, C e, C f, C g, C h, C i, C j)
1149 { addLoaderVA(a, b, c, d, e, f, g, h, i, j, N); }
1150 #undef C
1151 #undef N
1152
addLoaderVA(const char * s,...)1153 void __acc_cdecl_va Packer::addLoaderVA(const char *s, ...)
1154 {
1155 va_list ap;
1156 va_start(ap, s);
1157 linker->addLoader(s, ap);
1158 va_end(ap);
1159 }
1160
getLoader() const1161 upx_byte *Packer::getLoader() const
1162 {
1163 int size = -1;
1164 upx_byte *oloader = linker->getLoader(&size);
1165 if (oloader == NULL || size <= 0)
1166 throwBadLoader();
1167 return oloader;
1168 }
1169
getLoaderSize() const1170 int Packer::getLoaderSize() const
1171 {
1172 int size = -1;
1173 upx_byte *oloader = linker->getLoader(&size);
1174 if (oloader == NULL || size <= 0)
1175 throwBadLoader();
1176 return size;
1177 }
1178
hasLoaderSection(const char * name) const1179 bool Packer::hasLoaderSection(const char *name) const
1180 {
1181 void *section = linker->findSection(name, false);
1182 return section != NULL;
1183 }
1184
getLoaderSection(const char * name,int * slen) const1185 int Packer::getLoaderSection(const char *name, int *slen) const
1186 {
1187 int size = -1;
1188 int ostart = linker->getSection(name, &size);
1189 if (ostart < 0 || size <= 0)
1190 throwBadLoader();
1191 if (slen)
1192 *slen = size;
1193 return ostart;
1194 }
1195
1196 // same, but the size of the section may be == 0
getLoaderSectionStart(const char * name,int * slen) const1197 int Packer::getLoaderSectionStart(const char *name, int *slen) const
1198 {
1199 int size = -1;
1200 int ostart = linker->getSection(name, &size);
1201 if (ostart < 0 || size < 0)
1202 throwBadLoader();
1203 if (slen)
1204 *slen = size;
1205 return ostart;
1206 }
1207
1208
relocateLoader()1209 void Packer::relocateLoader()
1210 {
1211 linker->relocate();
1212
1213 #if 0
1214 // "relocate" packheader
1215 if (linker->findSection("UPX1HEAD", false))
1216 {
1217 int lsize = -1;
1218 int loff = getLoaderSectionStart("UPX1HEAD", &lsize);
1219 assert(lsize == ph.getPackHeaderSize());
1220 unsigned char *p = getLoader() + loff;
1221 assert(get_le32(p) == UPX_MAGIC_LE32);
1222 //patchPackHeader(p, lsize);
1223 ph.putPackHeader(p);
1224 }
1225 #endif
1226 }
1227
1228
1229 /*************************************************************************
1230 // Try compression with several methods and filters, choose the best
1231 / or first working one. Needs buildLoader().
1232 //
1233 // Required inputs:
1234 // this->ph
1235 // ulen
1236 // parm_ft
1237 // clevel
1238 // addvalue
1239 // buf_len (optional)
1240 //
1241 // - updates this->ph
1242 // - updates *ft
1243 // - i_ptr[] is restored to the original unfiltered version
1244 // - o_ptr[] contains the best compressed version
1245 //
1246 // filter_strategy:
1247 // n: try the first N filters, use best one
1248 // -1: try all filters, use first working one
1249 // -2: try only the opt->filter filter
1250 // -3: use no filter at all
1251 //
1252 // This has been prepared for generalization into class Packer so that
1253 // opt->all_methods and/or opt->all_filters are available for all
1254 // executable formats.
1255 //
1256 // It will replace the tryFilters() / compress() call sequence.
1257 //
1258 // 2006-02-15: hdr_buf and hdr_u_len are default empty input "header" array
1259 // to fix a 2-pass problem with Elf headers. As of today there can be
1260 // only one decompression method per executable output file, and that method
1261 // is the one that gives best compression for .text and loader. However,
1262 // the Elf headers precede .text in the output file, and are written first.
1263 // "--brute" compression often compressed the Elf headers using nrv2b
1264 // but the .text (and loader) with nrv2e. This often resulted in SIGSEGV
1265 // during decompression.
1266 // The workaround is for hdr_buf and hdr_u_len to describe the Elf headers
1267 // (typically less than 512 bytes) when .text is passed in, and include
1268 // them in the calculation of shortest output. Then the result
1269 // this->ph.method will say which [single] method to use for everything.
1270 // The Elf headers are never filtered. They are short enough (< 512 bytes)
1271 // that compressing them more than once per method (once here when choosing,
1272 // once again just before writing [because compressWithFilters discards])
1273 // is OK because of the simplicity of not having two output arrays.
1274 **************************************************************************/
1275
prepareMethods(int * methods,int ph_method,const int * all_methods)1276 static int prepareMethods(int *methods, int ph_method, const int *all_methods)
1277 {
1278 int nmethods = 0;
1279 if (!opt->all_methods || all_methods == NULL)
1280 {
1281 methods[nmethods++] = ph_method;
1282 return nmethods;
1283 }
1284 for (int mm = 0; all_methods[mm] != M_END; ++mm)
1285 {
1286 int method = all_methods[mm];
1287 if (method == M_ULTRA_BRUTE && !opt->ultra_brute)
1288 break;
1289 if (method == M_SKIP || method == M_ULTRA_BRUTE)
1290 continue;
1291 if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(method))
1292 continue;
1293 // use this method
1294 assert(Packer::isValidCompressionMethod(method));
1295 methods[nmethods++] = method;
1296 }
1297 return nmethods;
1298 }
1299
1300
prepareFilters(int * filters,int & filter_strategy,const int * all_filters)1301 static int prepareFilters(int *filters, int &filter_strategy,
1302 const int *all_filters)
1303 {
1304 int nfilters = 0;
1305
1306 // setup filter filter_strategy
1307 if (filter_strategy == 0)
1308 {
1309 if (opt->all_filters)
1310 // choose best from all available filters
1311 filter_strategy = INT_MAX;
1312 else if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters))
1313 // try opt->filter
1314 filter_strategy = -2;
1315 else
1316 // try the first working filter
1317 filter_strategy = -1;
1318 }
1319 assert(filter_strategy != 0);
1320
1321 if (filter_strategy == -3)
1322 goto done;
1323 if (filter_strategy == -2)
1324 {
1325 if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters))
1326 {
1327 filters[nfilters++] = opt->filter;
1328 goto done;
1329 }
1330 filter_strategy = -1;
1331 }
1332 assert(filter_strategy >= -1);
1333
1334 while (all_filters && *all_filters != FT_END)
1335 {
1336 int filter_id = *all_filters++;
1337 if (filter_id == FT_ULTRA_BRUTE && !opt->ultra_brute)
1338 break;
1339 if (filter_id == FT_SKIP || filter_id == FT_ULTRA_BRUTE)
1340 continue;
1341 if (filter_id == 0)
1342 continue;
1343 // use this filter
1344 assert(Filter::isValidFilter(filter_id));
1345 filters[nfilters++] = filter_id;
1346 if (filter_strategy >= 0 && nfilters >= filter_strategy)
1347 break;
1348 }
1349
1350 done:
1351 // filter_strategy now only means "stop after first successful filter"
1352 filter_strategy = (filter_strategy < 0) ? -1 : 0;
1353 // make sure that we have a "no filter" fallback
1354 for (int i = 0; i < nfilters; i++)
1355 if (filters[i] == 0)
1356 return nfilters;
1357 filters[nfilters++] = 0;
1358 return nfilters;
1359 }
1360
1361
compressWithFilters(upx_bytep i_ptr,unsigned i_len,upx_bytep o_ptr,upx_bytep f_ptr,unsigned f_len,const upx_bytep hdr_ptr,unsigned hdr_len,Filter * parm_ft,const unsigned overlap_range,const upx_compress_config_t * cconf,int filter_strategy,bool inhibit_compression_check)1362 void Packer::compressWithFilters(upx_bytep i_ptr, unsigned i_len,
1363 upx_bytep o_ptr,
1364 upx_bytep f_ptr, unsigned f_len,
1365 const upx_bytep hdr_ptr, unsigned hdr_len,
1366 Filter *parm_ft,
1367 const unsigned overlap_range,
1368 const upx_compress_config_t *cconf,
1369 int filter_strategy,
1370 bool inhibit_compression_check)
1371 {
1372 parm_ft->buf_len = f_len;
1373 // struct copies
1374 const PackHeader orig_ph = this->ph;
1375 PackHeader best_ph = this->ph;
1376 const Filter orig_ft = *parm_ft;
1377 Filter best_ft = *parm_ft;
1378 //
1379 best_ph.c_len = i_len;
1380 best_ph.overlap_overhead = 0;
1381 unsigned best_ph_lsize = 0;
1382 unsigned best_hdr_c_len = 0;
1383
1384 // preconditions
1385 assert(orig_ph.filter == 0);
1386 assert(orig_ft.id == 0);
1387
1388 // prepare methods and filters
1389 int methods[256];
1390 int nmethods = prepareMethods(methods, ph.method, getCompressionMethods(M_ALL, ph.level));
1391 assert(nmethods > 0); assert(nmethods < 256);
1392 int filters[256];
1393 int nfilters = prepareFilters(filters, filter_strategy, getFilters());
1394 assert(nfilters > 0); assert(nfilters < 256);
1395 #if 0
1396 printf("compressWithFilters: m(%d):", nmethods);
1397 for (int i = 0; i < nmethods; i++) printf(" %d", methods[i]);
1398 printf(" f(%d):", nfilters);
1399 for (int i = 0; i < nfilters; i++) printf(" %d", filters[i]);
1400 printf("\n");
1401 #endif
1402
1403 // update total_passes; previous (ui_total_passes > 0) means incremental
1404 if (uip->ui_total_passes > 0)
1405 uip->ui_total_passes -= 1;
1406 if (filter_strategy < 0)
1407 uip->ui_total_passes += nmethods;
1408 else
1409 uip->ui_total_passes += nfilters * nmethods;
1410
1411 // Working buffer for compressed data. Don't waste memory and allocate as needed.
1412 upx_bytep o_tmp = o_ptr;
1413 MemBuffer o_tmp_buf;
1414
1415 // compress using all methods/filters
1416 int nfilters_success_total = 0;
1417 for (int mm = 0; mm < nmethods; mm++) // for all methods
1418 {
1419 assert(isValidCompressionMethod(methods[mm]));
1420 unsigned hdr_c_len = 0;
1421 if (hdr_ptr != NULL && hdr_len)
1422 {
1423 if (nfilters_success_total != 0 && o_tmp == o_ptr)
1424 {
1425 // do not overwrite o_ptr
1426 o_tmp_buf.allocForCompression(UPX_MAX(hdr_len, i_len));
1427 o_tmp = o_tmp_buf;
1428 }
1429 int r = upx_compress(hdr_ptr, hdr_len, o_tmp, &hdr_c_len,
1430 NULL, methods[mm], 10, NULL, NULL);
1431 if (r != UPX_E_OK)
1432 throwInternalError("header compression failed");
1433 if (hdr_c_len >= hdr_len)
1434 throwInternalError("header compression size increase");
1435 }
1436 int nfilters_success_mm = 0;
1437 for (int ff = 0; ff < nfilters; ff++) // for all filters
1438 {
1439 assert(isValidFilter(filters[ff]));
1440 // get fresh packheader
1441 ph = orig_ph;
1442 ph.method = methods[mm];
1443 ph.filter = filters[ff];
1444 ph.overlap_overhead = 0;
1445 // get fresh filter
1446 Filter ft = orig_ft;
1447 ft.init(ph.filter, orig_ft.addvalue);
1448 // filter
1449 optimizeFilter(&ft, f_ptr, f_len);
1450 bool success = ft.filter(f_ptr, f_len);
1451 if (ft.id != 0 && ft.calls == 0)
1452 {
1453 // filter did not do anything - no need to call ft.unfilter()
1454 success = false;
1455 }
1456 if (!success)
1457 {
1458 // filter failed or was useless
1459 if (filter_strategy >= 0)
1460 {
1461 // adjust ui passes
1462 if (uip->ui_pass >= 0)
1463 uip->ui_pass++;
1464 }
1465 continue;
1466 }
1467 // filter success
1468 #if 0
1469 printf("filter: id 0x%02x size %6d, calls %5d/%5d/%3d/%5d/%5d, cto 0x%02x\n",
1470 ft.id, ft.buf_len, ft.calls, ft.noncalls, ft.wrongcalls, ft.firstcall, ft.lastcall, ft.cto);
1471 #endif
1472 if (nfilters_success_total != 0 && o_tmp == o_ptr)
1473 {
1474 o_tmp_buf.allocForCompression(i_len);
1475 o_tmp = o_tmp_buf;
1476 }
1477 nfilters_success_total++;
1478 nfilters_success_mm++;
1479 ph.filter_cto = ft.cto;
1480 ph.n_mru = ft.n_mru;
1481 // compress
1482 if (compress(i_ptr, i_len, o_tmp, cconf))
1483 {
1484 unsigned lsize = 0;
1485 // findOverlapOperhead() might be slow; omit if already too big.
1486 if (ph.c_len + lsize + hdr_c_len <= best_ph.c_len + best_ph_lsize + best_hdr_c_len)
1487 {
1488 // get results
1489 ph.overlap_overhead = findOverlapOverhead(o_tmp, i_ptr, overlap_range);
1490 buildLoader(&ft);
1491 lsize = getLoaderSize();
1492 assert(lsize > 0);
1493 }
1494 #if 0 //{
1495 printf("\n%2d %02x: %d +%4d +%3d = %d (best: %d +%4d +%3d = %d)\n", ph.method, ph.filter,
1496 ph.c_len, lsize, hdr_c_len, ph.c_len + lsize + hdr_c_len,
1497 best_ph.c_len, best_ph_lsize, best_hdr_c_len, best_ph.c_len + best_ph_lsize + best_hdr_c_len);
1498 #endif //}
1499 bool update = false;
1500 if (ph.c_len + lsize + hdr_c_len < best_ph.c_len + best_ph_lsize + best_hdr_c_len)
1501 update = true;
1502 else if (ph.c_len + lsize + hdr_c_len == best_ph.c_len + best_ph_lsize + best_hdr_c_len)
1503 {
1504 // prefer smaller loaders
1505 if (lsize + hdr_c_len < best_ph_lsize + best_hdr_c_len)
1506 update = true;
1507 else if (lsize + hdr_c_len == best_ph_lsize + best_hdr_c_len)
1508 {
1509 // prefer less overlap_overhead
1510 if (ph.overlap_overhead < best_ph.overlap_overhead)
1511 update = true;
1512 }
1513 }
1514 if (update)
1515 {
1516 assert((int)ph.overlap_overhead > 0);
1517 // update o_ptr[] with best version
1518 if (o_tmp != o_ptr)
1519 memcpy(o_ptr, o_tmp, ph.c_len);
1520 // save compression results
1521 best_ph = ph;
1522 best_ph_lsize = lsize;
1523 best_hdr_c_len = hdr_c_len;
1524 best_ft = ft;
1525 }
1526 }
1527 // restore - unfilter with verify
1528 ft.unfilter(f_ptr, f_len, true);
1529 if (filter_strategy < 0)
1530 break;
1531 }
1532 assert(nfilters_success_mm > 0);
1533 }
1534
1535 // postconditions 1)
1536 assert(nfilters_success_total > 0);
1537 assert(best_ph.u_len == orig_ph.u_len);
1538 assert(best_ph.filter == best_ft.id);
1539 assert(best_ph.filter_cto == best_ft.cto);
1540 // FIXME assert(best_ph.n_mru == best_ft.n_mru);
1541
1542 // copy back results
1543 this->ph = best_ph;
1544 *parm_ft = best_ft;
1545
1546 // Finally, check compression ratio.
1547 // Might be inhibited when blocksize < file_size, for instance.
1548 if (!inhibit_compression_check) {
1549 if (best_ph.c_len + best_ph_lsize >= best_ph.u_len)
1550 throwNotCompressible();
1551 if (!checkCompressionRatio(best_ph.u_len, best_ph.c_len))
1552 throwNotCompressible();
1553
1554 // postconditions 2)
1555 assert(best_ph.overlap_overhead > 0);
1556 }
1557
1558 // convenience
1559 buildLoader(&best_ft);
1560 }
1561
1562
1563 /*************************************************************************
1564 //
1565 **************************************************************************/
1566
compressWithFilters(Filter * ft,const unsigned overlap_range,const upx_compress_config_t * cconf,int filter_strategy,bool inhibit_compression_check)1567 void Packer::compressWithFilters(Filter *ft,
1568 const unsigned overlap_range,
1569 const upx_compress_config_t *cconf,
1570 int filter_strategy,
1571 bool inhibit_compression_check)
1572 {
1573 compressWithFilters(ft, overlap_range, cconf, filter_strategy,
1574 0, 0, 0, NULL, 0, inhibit_compression_check);
1575 }
1576
1577
compressWithFilters(Filter * ft,const unsigned overlap_range,const upx_compress_config_t * cconf,int filter_strategy,unsigned filter_off,unsigned ibuf_off,unsigned obuf_off,const upx_bytep hdr_ptr,unsigned hdr_len,bool inhibit_compression_check)1578 void Packer::compressWithFilters(Filter *ft,
1579 const unsigned overlap_range,
1580 const upx_compress_config_t *cconf,
1581 int filter_strategy,
1582 unsigned filter_off,
1583 unsigned ibuf_off,
1584 unsigned obuf_off,
1585 const upx_bytep hdr_ptr, unsigned hdr_len,
1586 bool inhibit_compression_check)
1587 {
1588 ibuf.checkState(); obuf.checkState();
1589
1590 upx_bytep i_ptr = ibuf + ibuf_off;
1591 unsigned i_len = ph.u_len;
1592 upx_bytep o_ptr = obuf + obuf_off;
1593 upx_bytep f_ptr = ibuf + filter_off;
1594 unsigned f_len = ft->buf_len ? ft->buf_len : i_len;
1595
1596 assert(f_ptr + f_len <= i_ptr + i_len);
1597
1598 compressWithFilters(i_ptr, i_len,
1599 o_ptr,
1600 f_ptr, f_len,
1601 hdr_ptr, hdr_len,
1602 ft, overlap_range, cconf, filter_strategy,
1603 inhibit_compression_check);
1604
1605 ibuf.checkState(); obuf.checkState();
1606 }
1607
1608 /* vim:set ts=4 sw=4 et: */
1609