diff --git a/NEWS b/NEWS index 4e915c55..72ef01d9 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ User visible changes for UPX ================================================================== Changes in 2.92 beta (XX XXX 200.): + * new option '--ultra-brute' which tries even more variants Changes in 2.91 beta (29 Nov 2006): * assorted bug fixes diff --git a/doc/upx.pod b/doc/upx.pod index 0d725336..f4e6def5 100644 --- a/doc/upx.pod +++ b/doc/upx.pod @@ -175,38 +175,13 @@ Note that compression level B<--best> can be somewhat slow for large files, but you definitely should use it when releasing a final version of your program. -Quick start for achieving the best compression ratio: - -=over 4 - -Try B. - -=back - -Details for achieving the best compression ratio: +Quick info for achieving the best compression ratio: =over 4 =item * -Use the compression level B<--best>. - -=item * - -Try one or both of the options B<--all-methods> and B<--all-filters>. - -=item * - -Try the option B<--crp-ms=NUMBER>. This uses more memory during compression -to achieve a (slightly) better compression ratio. - -NUMBER must be a decimal value from 10000 to 999999, inclusive. -The default value is 10000 (ten thousand). - -=item * - -Info: the option B<--brute> is an abbrevation for the options -B S<--all-methods> S<--all-filters> S<--crp-ms=999999>>. +Try B or even B. =item * @@ -855,7 +830,7 @@ Screensavers are supported, with the restriction that the filename must end with ".scr" (as screensavers are handled slightly different than normal exe files). -UPX compressed PE files has some minor memory overhead (usually in the +UPX compressed PE files have some minor memory overhead (usually in the 10 - 30 kbytes range) which can be seen by specifying the "-i" command line switch during compression. diff --git a/src/compress_lzma.cpp b/src/compress_lzma.cpp index fe19be92..327ccc8b 100644 --- a/src/compress_lzma.cpp +++ b/src/compress_lzma.cpp @@ -189,7 +189,7 @@ int upx_lzma_compress ( const upx_bytep src, unsigned src_len, const upx_compress_config_t *cconf_parm, upx_compress_result_t *cresult ) { - assert(method == M_LZMA); + assert(M_IS_LZMA(method)); assert(level > 0); assert(cresult != NULL); int r = UPX_E_ERROR; @@ -241,6 +241,12 @@ int upx_lzma_compress ( const upx_bytep src, unsigned src_len, pr[3].uintVal = lzma_compress_config_t::dict_size_t::default_value_c; pr[5].uintVal = lzma_compress_config_t::num_fast_bytes_t::default_value_c; #endif + // method overrides + if (method >= 0x100) { + pr[0].uintVal = (method >> 16) & 15; + pr[1].uintVal = (method >> 12) & 15; + pr[2].uintVal = (method >> 8) & 15; + } #if 0 // DEBUG - set sizes so that we use a maxmimum amount of stack. // These settings cause res->num_probs == 3147574, i.e. we will @@ -382,6 +388,7 @@ int upx_lzma_compress ( const upx_bytep src, unsigned src_len, error: *dst_len = os.Pos; + //printf("\nlzma_compress: %d: %u %u %u %u %u, %u - > %u\n", r, res->pos_bits, res->lit_pos_bits, res->lit_context_bits, res->dict_size, res->num_probs, src_len, *dst_len); return r; } @@ -402,7 +409,7 @@ int upx_lzma_decompress ( const upx_bytep src, unsigned src_len, int method, const upx_compress_result_t *cresult ) { - assert(method == M_LZMA); + assert(M_IS_LZMA(method)); // see res->num_probs above COMPILE_TIME_ASSERT(sizeof(CProb) == 2) COMPILE_TIME_ASSERT(LZMA_BASE_SIZE == 1846) @@ -479,7 +486,7 @@ int upx_lzma_test_overlap ( const upx_bytep buf, unsigned src_off, int method, const upx_compress_result_t *cresult ) { - assert(method == M_LZMA); + assert(M_IS_LZMA(method)); // FIXME - implement this // Note that Packer::verifyOverlappingDecompression() will diff --git a/src/conf.h b/src/conf.h index 98a80a8e..d2be69da 100644 --- a/src/conf.h +++ b/src/conf.h @@ -415,6 +415,7 @@ private: // compression methods - DO NOT CHANGE #define M_SKIP (-2) #define M_END (-1) +#define M_ULTRA_BRUTE (-3) #define M_NRV2B_LE32 2 #define M_NRV2B_8 3 #define M_NRV2B_LE16 4 @@ -434,7 +435,7 @@ private: #define M_IS_NRV2D(x) ((x) >= M_NRV2D_LE32 && (x) <= M_NRV2D_LE16) #define M_IS_NRV2E(x) ((x) >= M_NRV2E_LE32 && (x) <= M_NRV2E_LE16) #define M_IS_CL1B(x) ((x) >= M_CL1B_LE32 && (x) <= M_CL1B_LE16) -#define M_IS_LZMA(x) ((x) == M_LZMA) +#define M_IS_LZMA(x) (((x) & 255) == M_LZMA) #define M_IS_DEFLATE(x) ((x) == M_DEFLATE) diff --git a/src/main.cpp b/src/main.cpp index 4e6349a6..2196f77b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -499,7 +499,7 @@ static int do_option(int optc, const char *arg) case 'f': opt->force++; break; - case 902: + case 909: set_cmd(CMD_FILEINFO); break; case 'h': @@ -568,7 +568,7 @@ static int do_option(int optc, const char *arg) break; case 722: opt->all_methods_use_lzma = false; - if (opt->method == M_LZMA) + if (M_IS_LZMA(opt->method)) opt->method = -1; break; @@ -586,6 +586,9 @@ static int do_option(int optc, const char *arg) e_method(opt->method, optc); break; + case 902: // --ultra-brute + opt->ultra_brute = true; + /* fallthrough */ case 901: // --brute opt->all_methods = true; opt->all_methods_use_lzma = true; @@ -656,6 +659,7 @@ static int do_option(int optc, const char *arg) break; case 524: // --all-methods opt->all_methods = true; + opt->all_methods_use_lzma = true; opt->method = -1; break; case 525: // --exact @@ -871,10 +875,11 @@ static const struct mfx_option longopts[] = // commands {"best", 0x10, 0, 900}, // compress best {"brute", 0x10, 0, 901}, // compress best, brute force + {"ultra-brute", 0x10, 0, 902}, // compress best, brute force {"decompress", 0, 0, 'd'}, // decompress {"fast", 0x10, 0, '1'}, // compress faster - {"fileinfo", 0x10, 0, 902}, // display info about file - {"file-info", 0x10, 0, 902}, // display info about file + {"fileinfo", 0x10, 0, 909}, // display info about file + {"file-info", 0x10, 0, 909}, // display info about file {"help", 0, 0, 'h'+256}, // give help {"license", 0, 0, 'L'}, // display software license {"list", 0, 0, 'l'}, // list compressed exe @@ -1039,6 +1044,7 @@ static const struct mfx_option longopts[] = // commands {"best", 0x10, 0, 900}, // compress best {"brute", 0x10, 0, 901}, // compress best, brute force + {"ultra-brute", 0x10, 0, 902}, // compress best, brute force {"fast", 0x10, 0, '1'}, // compress faster // options diff --git a/src/options.h b/src/options.h index d4038ce2..e4e4ec30 100644 --- a/src/options.h +++ b/src/options.h @@ -49,6 +49,7 @@ struct options_t { int method; int level; // compression level 1..10 int filter; // preferred filter from Packer::getFilters() + bool ultra_brute; bool all_methods; // try all available compression methods ? bool all_methods_use_lzma; bool all_filters; // try all available filters ? diff --git a/src/p_djgpp2.cpp b/src/p_djgpp2.cpp index dcd20791..a584c3a8 100644 --- a/src/p_djgpp2.cpp +++ b/src/p_djgpp2.cpp @@ -97,9 +97,9 @@ void PackDjgpp2::buildLoader(const Filter *ft) addLoader("IDENTSTR,DJ2MAIN1", ft->id ? "DJCALLT1" : "", "DJ2MAIN2", - ph.method == M_LZMA ? "LZMA_INIT_STACK" : "", + M_IS_LZMA(ph.method) ? "LZMA_INIT_STACK" : "", getDecompressorSections(), - ph.method == M_LZMA ? "LZMA_DONE_STACK" : "", + M_IS_LZMA(ph.method) ? "LZMA_DONE_STACK" : "", "DJ2BSS00", NULL ); diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 88adcf6a..b8319f9a 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -464,7 +464,7 @@ PackLinuxElf32::buildLinuxLoader( if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc) throwInternalError("loader compression failed"); #if 0 //{ debugging only - if (M_LZMA==ph.method) { + if (M_IS_LZMA(ph.method)) { ucl_uint tmp_len = h.sz_unc; // LZMA uses this as EOF unsigned char *tmp = new unsigned char[tmp_len]; memset(tmp, 0, tmp_len); diff --git a/src/p_lx_exc.cpp b/src/p_lx_exc.cpp index f15a289a..ce5fe816 100644 --- a/src/p_lx_exc.cpp +++ b/src/p_lx_exc.cpp @@ -373,7 +373,7 @@ PackLinuxI386::buildLinuxLoader( addLoader("IDENTSTR", NULL); addLoader("LEXEC020", NULL); addLoader("FOLDEXEC", NULL); - if (ph.method == M_LZMA) { + if (M_IS_LZMA(ph.method)) { const lzma_compress_result_t *res = &ph.compress_result.result_lzma; acc_uint32e_t properties = // lc, lp, pb, dummy (res->lit_context_bits << 0) | diff --git a/src/p_ps1.cpp b/src/p_ps1.cpp index f31d9e88..5fbacfcd 100644 --- a/src/p_ps1.cpp +++ b/src/p_ps1.cpp @@ -300,7 +300,7 @@ void PackPs1::buildLoader(const Filter *) else if (ph.method == M_NRV2E_LE32) method = isCon ? "nrv2e.small,32bit.sub,nrv.done" : "nrv2e.32bit,nrv.done"; - else if (ph.method == M_LZMA) + else if (M_IS_LZMA(ph.method)) method = "nrv2b.small,8bit.sub,nrv.done,lzma.prep"; else throwInternalError("unknown compression method"); @@ -319,7 +319,7 @@ void PackPs1::buildLoader(const Filter *) foundBss = findBssSection(); - if (ph.method == M_LZMA && !buildPart2) + if (M_IS_LZMA(ph.method) && !buildPart2) { initLoader(stub_mipsel_r3000_ps1, sizeof(stub_mipsel_r3000_ps1)); addLoader("decompressor.start", @@ -329,7 +329,7 @@ void PackPs1::buildLoader(const Filter *) } else { - if (ph.method == M_LZMA && buildPart2) + if (M_IS_LZMA(ph.method) && buildPart2) { sz_lcpr = MemBuffer::getSizeForCompression(sz_lunc); unsigned char *cprLoader = new unsigned char[sz_lcpr]; @@ -338,7 +338,7 @@ void PackPs1::buildLoader(const Filter *) if (r != UPX_E_OK || sz_lcpr >= sz_lunc) throwInternalError("loader compression failed"); initLoader(stub_mipsel_r3000_ps1, sizeof(stub_mipsel_r3000_ps1), - (ph.method != M_LZMA || isCon) ? 0 : 1); + isCon || !M_IS_LZMA(ph.method) ? 0 : 1); linker->addSection("lzma.exec", cprLoader, sz_lcpr, 0); delete [] cprLoader; } @@ -352,7 +352,7 @@ void PackPs1::buildLoader(const Filter *) if (isCon) { - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) addLoader(!foundBss ? "con.start" : "bss.con.start", method, ih.tx_ptr & 0xffff ? "dec.ptr" : "dec.ptr.hi", @@ -368,7 +368,7 @@ void PackPs1::buildLoader(const Filter *) } else { - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) addLoader("cdb.start.lzma", "pad.code", "cdb.entry.lzma", method, "cdb.lzma.cpr", ih.tx_ptr & 0xffff ? "dec.ptr" : "dec.ptr.hi", "lzma.exec", NULL); @@ -441,10 +441,10 @@ bool PackPs1::findBssSection() if (0 < ALIGN_DOWN(bss_end - bss_start, 4) ) { - unsigned wkmem_sz = (ph.method == M_LZMA) ? 32768 : 800; + unsigned wkmem_sz = M_IS_LZMA(ph.method) ? 32768 : 800; unsigned end_offs = ih.tx_ptr + fdata_size + overlap; if (bss_end > (end_offs + wkmem_sz)) - return (isCon || (!isCon && (ph.method == M_LZMA))); + return isCon || (!isCon && M_IS_LZMA(ph.method)); else return false; } @@ -507,7 +507,7 @@ void PackPs1::pack(OutputFile *fo) unsigned lzma_init = 0; - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) { sz_lunc = getLoaderSize(); @@ -553,7 +553,7 @@ void PackPs1::pack(OutputFile *fo) } else { - d_len = (lsize - h_len) - getLoaderSectionStart((ph.method == M_LZMA) ? "cdb.entry.lzma" : "cdb.entry"); + d_len = (lsize - h_len) - getLoaderSectionStart(M_IS_LZMA(ph.method) ? "cdb.entry.lzma" : "cdb.entry"); e_len = (lsize - d_len) - h_len; } @@ -561,10 +561,10 @@ void PackPs1::pack(OutputFile *fo) linker->defineSymbol("SC", MIPS_LO(sa_cnt > (0x10000 << 2) ? sa_cnt >> 5 : sa_cnt >> 2)); linker->defineSymbol("DECO", decomp_data_start); - linker->defineSymbol("ldr_sz", (ph.method == M_LZMA ? sz_lunc + 16 : (d_len-pad_code))); + linker->defineSymbol("ldr_sz", M_IS_LZMA(ph.method) ? sz_lunc + 16 : (d_len-pad_code)); if (foundBss) - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) linker->defineSymbol("wrkmem", bss_end - 160 - getDecompressorWrkmemSize() - (sz_lunc + 16)); else @@ -588,7 +588,7 @@ void PackPs1::pack(OutputFile *fo) ibuf.clear(0,fdata_size); upx_bytep paddata = ibuf; - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) { linker->defineSymbol("lzma_init_off", lzma_init); linker->defineSymbol("gb_e", linker->getSymbolOffset("gb8_e")); @@ -600,7 +600,7 @@ void PackPs1::pack(OutputFile *fo) if (isCon) { linker->defineSymbol("PAD", pad_code); - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) linker->defineSymbol("DCRT", (entry + getLoaderSectionStart("lzma.exec"))); else linker->defineSymbol("DCRT", (entry + (e_len - d_len))); @@ -609,7 +609,7 @@ void PackPs1::pack(OutputFile *fo) { linker->defineSymbol("PSVR", FIX_PSVR); linker->defineSymbol("CPDO", comp_data_start); - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) linker->defineSymbol("lzma_cpr", getLoaderSectionStart("lzma.exec") - getLoaderSectionStart("cdb.entry.lzma")); } @@ -621,7 +621,7 @@ void PackPs1::pack(OutputFile *fo) memcpy(loader, getLoader(), lsize); patchPackHeader(loader, lsize); - if (!isCon && ph.method == M_LZMA && (HD_CODE_OFS + d_len + h_len) > CD_SEC) + if (!isCon && M_IS_LZMA(ph.method) && (HD_CODE_OFS + d_len + h_len) > CD_SEC) throwInternalError("lzma --boot-only loader > 2048"); // ps1_exe_t structure @@ -655,7 +655,7 @@ void PackPs1::pack(OutputFile *fo) printf("%-13s: eof in mem OF : %08X bytes\n", getName(), (unsigned int) oh.tx_ptr + oh.tx_len); unsigned char i = 0; if (isCon) { if (foundBss) i = 1; } - else { i = 2; if (ph.method == M_LZMA) { if (!foundBss) i = 3; else i = 4; } } + else { i = 2; if (M_IS_LZMA(ph.method)) { if (!foundBss) i = 3; else i = 4; } } const char *loader_method[] = { "con/stack", "con/bss", "cdb", "cdb/stack", "cdb/bss" }; char method_name[32+1]; set_method_name(method_name, sizeof(method_name), ph.method, ph.level); printf("%-13s: methods : %s, %s\n", getName(), method_name, loader_method[i]); diff --git a/src/p_vmlinz.cpp b/src/p_vmlinz.cpp index f25be791..fa5f67c8 100644 --- a/src/p_vmlinz.cpp +++ b/src/p_vmlinz.cpp @@ -410,7 +410,7 @@ void PackBvmlinuzI386::pack(OutputFile *fo) const unsigned lsize = getLoaderSize(); - if (ph.method == M_LZMA) { + if (M_IS_LZMA(ph.method)) { const lzma_compress_result_t *res = &ph.compress_result.result_lzma; acc_uint32e_t properties = // lc, lp, pb, dummy (res->lit_context_bits << 0) | diff --git a/src/packer.cpp b/src/packer.cpp index 92e9eb2a..a976a3d8 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -163,7 +163,9 @@ bool Packer::testUnpackFormat(int format) const bool ph_skipVerify(const PackHeader &ph) { - if (ph.method == M_LZMA) + if (M_IS_DEFLATE(ph.method)) + return false; + if (M_IS_LZMA(ph.method)) return false; if (ph.level > 1) return false; @@ -1267,9 +1269,11 @@ void Packer::compressWithFilters(Filter *parm_ft, int nmethods = 0; for (int mm = 0; methods[mm] != M_END; ++mm) { - if (methods[mm] == M_SKIP) + if (methods[mm] == M_ULTRA_BRUTE && !opt->ultra_brute) + break; + if (methods[mm] == M_SKIP || methods[mm] == M_ULTRA_BRUTE) continue; - if (opt->all_methods && !opt->all_methods_use_lzma && methods[mm] == M_LZMA) + if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(methods[mm])) continue; assert(isValidCompressionMethod(methods[mm])); nmethods++; @@ -1290,9 +1294,11 @@ void Packer::compressWithFilters(Filter *parm_ft, int nfilters_success = 0; for (int mm = 0; methods[mm] != M_END; ++mm) // for all methods { - if (methods[mm] == M_SKIP) + if (methods[mm] == M_ULTRA_BRUTE && !opt->ultra_brute) + break; + if (methods[mm] == M_SKIP || methods[mm] == M_ULTRA_BRUTE) continue; - if (opt->all_methods && !opt->all_methods_use_lzma && methods[mm] == M_LZMA) + if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(methods[mm])) continue; unsigned hdr_c_len = 0; if (hdr_buf && hdr_u_len) diff --git a/src/packer_c.cpp b/src/packer_c.cpp index bdd8acaa..d0c0bd27 100644 --- a/src/packer_c.cpp +++ b/src/packer_c.cpp @@ -38,20 +38,24 @@ bool Packer::isValidCompressionMethod(int method) { -#if 1 && !defined(WITH_LZMA) - if (method == M_LZMA) { + if (M_IS_LZMA(method)) { +#if !defined(WITH_LZMA) assert(0 && "Internal error - LZMA not compiled in"); - } +#else + return true; #endif + } return (method >= M_NRV2B_LE32 && method <= M_LZMA); } const int *Packer::getDefaultCompressionMethods_8(int method, int level, int small) const { - static const int m_nrv2b[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_LZMA, M_END }; - static const int m_nrv2d[] = { M_NRV2D_8, M_NRV2B_8, M_NRV2E_8, M_LZMA, M_END }; - static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_NRV2D_8, M_LZMA, M_END }; +#define M_LZMA_003 (M_LZMA | 0x00300) +#define M_LZMA_407 (M_LZMA | 0x40700) + static const int m_nrv2b[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END }; + static const int m_nrv2d[] = { M_NRV2D_8, M_NRV2B_8, M_NRV2E_8, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END }; + static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_NRV2D_8, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END }; static const int m_cl1b[] = { M_CL1B_8, M_END }; static const int m_lzma[] = { M_LZMA, M_END }; @@ -76,9 +80,9 @@ const int *Packer::getDefaultCompressionMethods_8(int method, int level, int sma const int *Packer::getDefaultCompressionMethods_le32(int method, int level, int small) const { - static const int m_nrv2b[] = { M_NRV2B_LE32, M_NRV2D_LE32, M_NRV2E_LE32, M_LZMA, M_END }; - static const int m_nrv2d[] = { M_NRV2D_LE32, M_NRV2B_LE32, M_NRV2E_LE32, M_LZMA, M_END }; - static const int m_nrv2e[] = { M_NRV2E_LE32, M_NRV2B_LE32, M_NRV2D_LE32, M_LZMA, M_END }; + static const int m_nrv2b[] = { M_NRV2B_LE32, M_NRV2D_LE32, M_NRV2E_LE32, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END }; + static const int m_nrv2d[] = { M_NRV2D_LE32, M_NRV2B_LE32, M_NRV2E_LE32, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END }; + static const int m_nrv2e[] = { M_NRV2E_LE32, M_NRV2B_LE32, M_NRV2D_LE32, M_LZMA, M_ULTRA_BRUTE, M_LZMA_003, M_LZMA_407, M_END }; static const int m_cl1b[] = { M_CL1B_LE32, M_END }; static const int m_lzma[] = { M_LZMA, M_END }; @@ -206,7 +210,7 @@ const char *Packer::getDecompressorSections() const return opt->small ? nrv2e_le32_small : nrv2e_le32_fast; if (ph.method == M_CL1B_LE32) return opt->small ? cl1b_le32_small : cl1b_le32_fast; - if (ph.method == M_LZMA) { + if (M_IS_LZMA(ph.method)) { if (UPX_F_LINUX_ELF_i386 ==ph.format || UPX_F_LINUX_ELFI_i386 ==ph.format || UPX_F_LINUX_ELF64_AMD ==ph.format @@ -225,7 +229,7 @@ const char *Packer::getDecompressorSections() const unsigned Packer::getDecompressorWrkmemSize() const { unsigned size = 0; - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) { const lzma_compress_result_t *res = &ph.compress_result.result_lzma; // FIXME - this is for i386 only @@ -249,7 +253,7 @@ void Packer::defineDecompressorSymbols() // ELF calls the decompressor many times; the parameters change! return; } - if (ph.method == M_LZMA) + if (M_IS_LZMA(ph.method)) { const lzma_compress_result_t *res = &ph.compress_result.result_lzma; // FIXME - this is for i386 only