From 8875470b37b2661732b200dd976944ffb846b937 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Wed, 6 Dec 2006 07:27:23 +0100 Subject: [PATCH] Refactored compressWithFilters(). --- src/compress_ucl.cpp | 2 +- src/conf.h | 127 +++++++++++++---------- src/filter.cpp | 22 +++- src/filter.h | 1 + src/p_armpe.cpp | 23 ++--- src/p_com.cpp | 13 +-- src/p_djgpp2.cpp | 2 +- src/p_elks.cpp | 2 +- src/p_exe.cpp | 19 ++-- src/p_lx_interp.cpp | 6 +- src/p_mach.cpp | 2 +- src/p_ps1.cpp | 2 +- src/p_tmt.cpp | 5 +- src/p_tos.cpp | 2 +- src/p_unix.cpp | 17 ++-- src/p_vmlinx.cpp | 6 +- src/p_vmlinz.cpp | 4 +- src/p_w32pe.cpp | 8 +- src/packer.cpp | 237 +++++++++++++++++++++++-------------------- src/packer.h | 7 +- src/packer_c.cpp | 58 +++++------ src/packer_f.cpp | 23 ++--- 22 files changed, 311 insertions(+), 277 deletions(-) diff --git a/src/compress_ucl.cpp b/src/compress_ucl.cpp index 683cd985..df1dde42 100644 --- a/src/compress_ucl.cpp +++ b/src/compress_ucl.cpp @@ -135,7 +135,7 @@ int upx_ucl_compress ( const upx_bytep src, unsigned src_len, // prepare bit-buffer settings cconf.bb_endian = 0; cconf.bb_size = 0; - if (method >= M_NRV2B_LE32 && method <= M_CL1B_LE16) + if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16) { static const unsigned char sizes[3] = {32, 8, 16}; cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3]; diff --git a/src/conf.h b/src/conf.h index dbad4feb..8c13418b 100644 --- a/src/conf.h +++ b/src/conf.h @@ -187,34 +187,6 @@ #define upx_byte unsigned char #define upx_bytep upx_byte * -#define UPX_E_OK (0) -#define UPX_E_ERROR (-1) -#define UPX_E_OUT_OF_MEMORY (-2) -#define UPX_E_NOT_COMPRESSIBLE (-3) -#define UPX_E_INPUT_OVERRUN (-4) -#define UPX_E_OUTPUT_OVERRUN (-5) -#define UPX_E_LOOKBEHIND_OVERRUN (-6) -#define UPX_E_EOF_NOT_FOUND (-7) -#define UPX_E_INPUT_NOT_CONSUMED (-8) -#define UPX_E_NOT_YET_IMPLEMENTED (-9) -#define UPX_E_INVALID_ARGUMENT (-10) - -struct upx_callback_t; -#define upx_callback_p upx_callback_t * -typedef void* (__acc_cdecl *upx_alloc_func_t) - (upx_callback_p self, unsigned items, unsigned size); -typedef void (__acc_cdecl *upx_free_func_t) - (upx_callback_p self, void* ptr); -typedef void (__acc_cdecl *upx_progress_func_t) - (upx_callback_p, unsigned, unsigned); - -struct upx_callback_t -{ - upx_progress_func_t nprogress; - void *user; - - void reset() { memset(this, 0, sizeof(*this)); } -}; /************************************************************************* @@ -414,31 +386,23 @@ private: #define EXIT_INTERNAL 1 -// 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 -#define M_NRV2D_LE32 5 -#define M_NRV2D_8 6 -#define M_NRV2D_LE16 7 -#define M_NRV2E_LE32 8 -#define M_NRV2E_8 9 -#define M_NRV2E_LE16 10 -#define M_CL1B_LE32 11 -#define M_CL1B_8 12 -#define M_CL1B_LE16 13 -#define M_LZMA 14 -#define M_DEFLATE 15 /* zlib */ +// magic constants for patching +#define UPX_MAGIC_LE32 0x21585055 /* "UPX!" */ +#define UPX_MAGIC2_LE32 0xD5D0D8A1 -#define M_IS_NRV2B(x) ((x) >= M_NRV2B_LE32 && (x) <= M_NRV2B_LE16) -#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) & 255) == M_LZMA) -#define M_IS_DEFLATE(x) ((x) == M_DEFLATE) + +// upx_compress() error codes +#define UPX_E_OK (0) +#define UPX_E_ERROR (-1) +#define UPX_E_OUT_OF_MEMORY (-2) +#define UPX_E_NOT_COMPRESSIBLE (-3) +#define UPX_E_INPUT_OVERRUN (-4) +#define UPX_E_OUTPUT_OVERRUN (-5) +#define UPX_E_LOOKBEHIND_OVERRUN (-6) +#define UPX_E_EOF_NOT_FOUND (-7) +#define UPX_E_INPUT_NOT_CONSUMED (-8) +#define UPX_E_NOT_YET_IMPLEMENTED (-9) +#define UPX_E_INVALID_ARGUMENT (-10) // Executable formats. Note: big endian types are >= 128. @@ -478,8 +442,61 @@ private: #define UPX_F_LINUX_ELF32_ARMBE 133 -#define UPX_MAGIC_LE32 0x21585055 /* "UPX!" */ -#define UPX_MAGIC2_LE32 0xD5D0D8A1 +// compression methods - DO NOT CHANGE +#define M_END (-1) +#define M_SKIP (-2) +#define M_ULTRA_BRUTE (-3) +#define M_NRV2B_LE32 2 +#define M_NRV2B_8 3 +#define M_NRV2B_LE16 4 +#define M_NRV2D_LE32 5 +#define M_NRV2D_8 6 +#define M_NRV2D_LE16 7 +#define M_NRV2E_LE32 8 +#define M_NRV2E_8 9 +#define M_NRV2E_LE16 10 +//#define M_CL1B_LE32 11 +//#define M_CL1B_8 12 +//#define M_CL1B_LE16 13 +#define M_LZMA 14 +#define M_DEFLATE 15 /* zlib */ + +#define M_IS_NRV2B(x) ((x) >= M_NRV2B_LE32 && (x) <= M_NRV2B_LE16) +#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) & 255) == M_LZMA) +#define M_IS_DEFLATE(x) ((x) == M_DEFLATE) + + +// filters - DO NOT CHANGE +#define FT_END (-1) +#define FT_SKIP (-2) +#define FT_ULTRA_BRUTE (-3) + + +/************************************************************************* +// compression - callback_t +**************************************************************************/ + +struct upx_callback_t; +#define upx_callback_p upx_callback_t * +#if 0 +typedef void* (__acc_cdecl *upx_alloc_func_t) + (upx_callback_p self, unsigned items, unsigned size); +typedef void (__acc_cdecl *upx_free_func_t) + (upx_callback_p self, void* ptr); +#endif +typedef void (__acc_cdecl *upx_progress_func_t) + (upx_callback_p, unsigned, unsigned); + +struct upx_callback_t +{ + upx_progress_func_t nprogress; + void *user; + + void reset() { memset(this, 0, sizeof(*this)); } +}; /************************************************************************* @@ -588,6 +605,8 @@ struct upx_compress_config_t void reset() { conf_lzma.reset(); conf_ucl.reset(); conf_zlib.reset(); } }; +#define NULL_cconf ((upx_compress_config_t *) NULL) + /************************************************************************* // compression - result_t diff --git a/src/filter.cpp b/src/filter.cpp index 595335be..9046f600 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -61,10 +61,10 @@ const FilterImp::FilterEntry *FilterImp::getFilter(int id) memset(filter_map, 0xff, sizeof(filter_map)); for (int i = 0; i < n_filters; i++) { - int fid = filters[i].id; - assert(fid >= 0 && fid <= 255); - assert(filter_map[fid] == 0xff); - filter_map[fid] = (unsigned char) i; + int filter_id = filters[i].id; + assert(filter_id >= 0 && filter_id <= 255); + assert(filter_map[filter_id] == 0xff); + filter_map[filter_id] = (unsigned char) i; } done = true; } @@ -85,6 +85,20 @@ bool Filter::isValidFilter(int filter_id) return fe != NULL; } +bool Filter::isValidFilter(int filter_id, const int *allowed_filters) +{ + if (!isValidFilter(filter_id)) + return false; + if (filter_id == 0) + return true; + if (allowed_filters == NULL) + return false; + while (*allowed_filters != FT_END) + if (*allowed_filters++ == filter_id) + return true; + return false; +} + /************************************************************************* // high level API diff --git a/src/filter.h b/src/filter.h index 35087040..20be1369 100644 --- a/src/filter.h +++ b/src/filter.h @@ -62,6 +62,7 @@ public: bool scan(const upx_byte *buf, unsigned buf_len); static bool isValidFilter(int filter_id); + static bool isValidFilter(int filter_id, const int *allowed_filters); public: // Will be set by each call to filter()/unfilter(). diff --git a/src/p_armpe.cpp b/src/p_armpe.cpp index 324eb1cb..164d9cb0 100644 --- a/src/p_armpe.cpp +++ b/src/p_armpe.cpp @@ -115,19 +115,18 @@ PackArmPe::~PackArmPe() const int *PackArmPe::getCompressionMethods(int method, int level) const { - static const int m_nrv2b[] = { M_NRV2B_8, M_NRV2E_8, M_LZMA, M_END }; - static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_LZMA, M_END }; + static const int m_all[] = { M_NRV2B_8, M_NRV2E_8, M_LZMA, M_END }; static const int m_lzma[] = { M_LZMA, M_END }; + static const int m_nrv2b[] = { M_NRV2B_8, M_END }; + static const int m_nrv2e[] = { M_NRV2E_8, M_END }; if (!use_thumb_stub) return getDefaultCompressionMethods_8(method, level); - if (M_IS_NRV2B(method)) - return m_nrv2b; - if (M_IS_NRV2E(method)) - return m_nrv2e; - if (M_IS_LZMA(method)) - return m_lzma; + if (method == -1) return m_all; + if (M_IS_LZMA(method)) return m_lzma; + if (M_IS_NRV2B(method)) return m_nrv2b; + if (M_IS_NRV2E(method)) return m_nrv2e; return m_nrv2e; } @@ -698,20 +697,20 @@ void PackArmPe::pack(OutputFile *fo) ft.buf_len = ih.codesize; ft.addvalue = ih.codebase - rvamin; // compress - int strategy = allow_filter ? 0 : -3; + int filter_strategy = allow_filter ? 0 : -3; // disable filters for files with broken headers if (ih.codebase + ih.codesize > ph.u_len) { ft.buf_len = 1; - strategy = -3; + filter_strategy = -3; } // limit stack size needed for runtime decompression upx_compress_config_t cconf; cconf.reset(); cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack - compressWithFilters(&ft, 2048, strategy, - NULL, &cconf, ih.codebase, rvamin); + compressWithFilters(&ft, 2048, &cconf, filter_strategy, + ih.codebase, rvamin); // info: see buildLoader() newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1; /* diff --git a/src/p_com.cpp b/src/p_com.cpp index a000b9be..427e943f 100644 --- a/src/p_com.cpp +++ b/src/p_com.cpp @@ -45,16 +45,11 @@ static const const int *PackCom::getCompressionMethods(int method, int level) const { - static const int m_nrv2b[] = { M_NRV2B_LE16, -1 }; - if (M_IS_NRV2B(method)) - return m_nrv2b; + static const int m_nrv2b[] = { M_NRV2B_LE16, M_END }; #if 0 - // NOT IMPLEMENTED - static const int m_nrv2d[] = { M_NRV2D_LE16, -1 }; - if (M_IS_NRV2D(method)) - return m_nrv2d; + static const int m_nrv2d[] = { M_NRV2D_LE16, M_END }; #endif - UNUSED(level); + UNUSED(method); UNUSED(level); return m_nrv2b; } @@ -202,7 +197,7 @@ void PackCom::pack(OutputFile *fo) ft.addvalue = getCallTrickOffset(); // compress const unsigned overlap_range = ph.u_len < 0xFE00 - ft.addvalue ? 32 : 0; - compressWithFilters(&ft, overlap_range); + compressWithFilters(&ft, overlap_range, NULL_cconf); const int lsize = getLoaderSize(); MemBuffer loader(lsize); diff --git a/src/p_djgpp2.cpp b/src/p_djgpp2.cpp index a584c3a8..7986eb81 100644 --- a/src/p_djgpp2.cpp +++ b/src/p_djgpp2.cpp @@ -325,7 +325,7 @@ void PackDjgpp2::pack(OutputFile *fo) upx_compress_config_t cconf; cconf.reset(); // limit stack size needed for runtime decompression cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack - compressWithFilters(&ft, 512, 0, NULL, &cconf); + compressWithFilters(&ft, 512, &cconf); // patch coff header #2 const unsigned lsize = getLoaderSize(); diff --git a/src/p_elks.cpp b/src/p_elks.cpp index f6161a22..1f6f6742 100644 --- a/src/p_elks.cpp +++ b/src/p_elks.cpp @@ -112,7 +112,7 @@ void PackElks8086::pack(OutputFile *fo) ft.buf_len = ph.u_len; ft.addvalue = kernel_entry; // compress - compressWithFilters(&ft, overlap_range); + compressWithFilters(&ft, overlap_range, NULL_cconf); const unsigned lsize = getLoaderSize(); MemBuffer loader(lsize); diff --git a/src/p_exe.cpp b/src/p_exe.cpp index 85e9ec83..f39faae3 100644 --- a/src/p_exe.cpp +++ b/src/p_exe.cpp @@ -58,17 +58,16 @@ PackExe::PackExe(InputFile *f) : const int *PackExe::getCompressionMethods(int method, int level) const { - static const int m_nrv2b[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_END }; - static const int m_nrv2d[] = { M_NRV2D_8, M_NRV2B_8, M_NRV2E_8, M_END }; - static const int m_nrv2e[] = { M_NRV2E_8, M_NRV2B_8, M_NRV2D_8, M_END }; + static const int m_all[] = { M_NRV2B_8, M_NRV2D_8, M_NRV2E_8, M_END }; + static const int m_nrv2b[] = { M_NRV2B_8, M_END }; + static const int m_nrv2d[] = { M_NRV2D_8, M_END }; + static const int m_nrv2e[] = { M_NRV2E_8, M_END }; + if (method == -1) return m_all; + if (M_IS_NRV2B(method)) return m_nrv2b; + if (M_IS_NRV2D(method)) return m_nrv2d; + if (M_IS_NRV2E(method)) return m_nrv2e; bool small = ih_imagesize <= 256*1024; - if (M_IS_NRV2B(method)) - return m_nrv2b; - if (M_IS_NRV2D(method)) - return m_nrv2d; - if (M_IS_NRV2E(method)) - return m_nrv2e; if (level == 1 || small) return m_nrv2b; return m_nrv2e; @@ -430,7 +429,7 @@ void PackExe::pack(OutputFile *fo) // compress (max_match = 8192) upx_compress_config_t cconf; cconf.reset(); cconf.conf_ucl.max_match = MAXMATCH; - compressWithFilters(&ft, 32, 0, NULL, &cconf); + compressWithFilters(&ft, 32, &cconf); if (ph.max_run_found + ph.max_match_found > 0x8000) throwCantPack("decompressor limit exceeded, send a bugreport"); diff --git a/src/p_lx_interp.cpp b/src/p_lx_interp.cpp index e0e01591..ab1dd54b 100644 --- a/src/p_lx_interp.cpp +++ b/src/p_lx_interp.cpp @@ -164,9 +164,9 @@ void PackLinuxElf32x86interp::pack3(OutputFile *fo, Filter &/*ft*/) ph.method = M_NRV2E_LE32; addLoader(getDecompressorSections(), NULL); addLoader("LXPTI090", NULL); - addLoader("LXPTI043", NULL); - ph.method = M_CL1B_LE32; addLoader(getDecompressorSections(), NULL); - addLoader("LXPTI090", NULL); + //addLoader("LXPTI043", NULL); + //ph.method = M_CL1B_LE32; addLoader(getDecompressorSections(), NULL); + //addLoader("LXPTI090", NULL); addLoader("LXPTI091", NULL); diff --git a/src/p_mach.cpp b/src/p_mach.cpp index 508047ac..e81a73bd 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -53,7 +53,7 @@ PackMachPPC32::~PackMachPPC32() const int *PackMachPPC32::getCompressionMethods(int /*method*/, int /*level*/) const { // There really is no LE bias in M_NRV2E_LE32. - static const int m_nrv2e[] = { M_NRV2E_LE32, -1 }; + static const int m_nrv2e[] = { M_NRV2E_LE32, M_END }; return m_nrv2e; } diff --git a/src/p_ps1.cpp b/src/p_ps1.cpp index 5fbacfcd..78de9813 100644 --- a/src/p_ps1.cpp +++ b/src/p_ps1.cpp @@ -491,7 +491,7 @@ void PackPs1::pack(OutputFile *fo) upx_compress_config_t cconf; cconf.reset(); cconf.conf_ucl.max_match = 65535; cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack - compressWithFilters(&ft, sa_cnt, 0, NULL, &cconf); + compressWithFilters(&ft, sa_cnt, &cconf); if (overlap) { diff --git a/src/p_tmt.cpp b/src/p_tmt.cpp index cc415a39..40b3476d 100644 --- a/src/p_tmt.cpp +++ b/src/p_tmt.cpp @@ -249,7 +249,10 @@ void PackTmt::pack(OutputFile *fo) Filter ft(ph.level); ft.buf_len = usize; // compress - compressWithFilters(&ft, 512); + upx_compress_config_t cconf; cconf.reset(); + // limit stack size needed for runtime decompression + cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack + compressWithFilters(&ft, 512, &cconf); const unsigned lsize = getLoaderSize(); const unsigned s_point = getLoaderSection("TMTMAIN1"); diff --git a/src/p_tos.cpp b/src/p_tos.cpp index 9eb9bb30..6983626c 100644 --- a/src/p_tos.cpp +++ b/src/p_tos.cpp @@ -508,7 +508,7 @@ void PackTos::pack(OutputFile *fo) upx_compress_config_t cconf; cconf.reset(); cconf.conf_ucl.max_match = 65535; cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack - compressWithFilters(&ft, 512, 0, NULL, &cconf); + compressWithFilters(&ft, 512, &cconf); // // multipass buildLoader() diff --git a/src/p_unix.cpp b/src/p_unix.cpp index 4f682295..fa5d7e60 100644 --- a/src/p_unix.cpp +++ b/src/p_unix.cpp @@ -125,8 +125,8 @@ int PackUnix::getStrategy(Filter &/*ft*/) // Called just before reading and compressing each block. // Might want to adjust blocksize, etc. - // If user specified the filter, then use it (-2==strategy). - // Else try the first two filters, and pick the better (2==strategy). + // If user specified the filter, then use it (-2==filter_strategy). + // Else try the first two filters, and pick the better (2==filter_strategy). return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2)); } @@ -151,9 +151,9 @@ void PackUnix::pack2(OutputFile *fo, Filter &ft) // which assumes it has free choice on each call [block]. // And if the choices aren't the same on each block, // then un-filtering will give incorrect results. - int strategy = getStrategy(ft); + int filter_strategy = getStrategy(ft); if (file_size > (off_t)blocksize) - strategy = -3; // no filters + filter_strategy = -3; // no filters int l = fi->readx(ibuf, UPX_MIN(blocksize, remaining)); remaining -= l; @@ -170,7 +170,7 @@ void PackUnix::pack2(OutputFile *fo, Filter &ft) // that is, AFTER filtering. We want BEFORE filtering, // so that decompression checks the end-to-end checksum. unsigned const end_u_adler = upx_adler32(ibuf, ph.u_len, ph.u_adler); - compressWithFilters(&ft, OVERHEAD, strategy); + compressWithFilters(&ft, OVERHEAD, NULL_cconf, filter_strategy); if (ph.c_len < ph.u_len) { ph.overlap_overhead = OVERHEAD; @@ -318,7 +318,7 @@ void PackUnix::packExtent( } fi->seek(x.offset, SEEK_SET); for (off_t rest = x.size; 0 != rest; ) { - int const strategy = getStrategy(*ft); + int const filter_strategy = getStrategy(*ft); int l = fi->readx(ibuf, UPX_MIN(rest, (off_t)blocksize)); if (l == 0) { break; @@ -345,9 +345,8 @@ void PackUnix::packExtent( ft->id = 0; ft->cto = 0; - compressWithFilters(ft, OVERHEAD, strategy, - NULL, NULL, 0, 0, // those 4 args are the defaults - hdr_ibuf, hdr_u_len); + compressWithFilters(ft, OVERHEAD, NULL_cconf, filter_strategy, + 0, 0, hdr_ibuf, hdr_u_len); } else { (void) compress(ibuf, obuf); // ignore return value diff --git a/src/p_vmlinx.cpp b/src/p_vmlinx.cpp index 89ba93f0..dc203b9c 100644 --- a/src/p_vmlinx.cpp +++ b/src/p_vmlinx.cpp @@ -78,8 +78,8 @@ int PackVmlinuxI386::getStrategy(Filter &/*ft*/) // Called just before reading and compressing each block. // Might want to adjust blocksize, etc. - // If user specified the filter, then use it (-2==strategy). - // Else try the first two filters, and pick the better (2==strategy). + // If user specified the filter, then use it (-2==filter_strategy). + // Else try the first two filters, and pick the better (2==filter_strategy). return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2)); } @@ -309,7 +309,7 @@ void PackVmlinuxI386::pack(OutputFile *fo) upx_compress_config_t cconf; cconf.reset(); // limit stack size needed for runtime decompression cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack - compressWithFilters(&ft, 512, getStrategy(ft), getFilters(), &cconf); + compressWithFilters(&ft, 512, &cconf, getStrategy(ft)); const unsigned lsize = getLoaderSize(); diff --git a/src/p_vmlinz.cpp b/src/p_vmlinz.cpp index fa5f67c8..ff47ea57 100644 --- a/src/p_vmlinz.cpp +++ b/src/p_vmlinz.cpp @@ -316,7 +316,7 @@ void PackVmlinuzI386::pack(OutputFile *fo) upx_compress_config_t cconf; cconf.reset(); // limit stack size needed for runtime decompression cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack - compressWithFilters(&ft, 512, 0, NULL, &cconf); + compressWithFilters(&ft, 512, &cconf); const unsigned lsize = getLoaderSize(); @@ -401,7 +401,7 @@ void PackBvmlinuzI386::pack(OutputFile *fo) upx_compress_config_t cconf; cconf.reset(); // limit stack size needed for runtime decompression cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack - compressWithFilters(&ft, 512, 0, NULL, &cconf); + compressWithFilters(&ft, 512, &cconf); // align everything to dword boundary - it is easier to handle unsigned c_len = ph.c_len; diff --git a/src/p_w32pe.cpp b/src/p_w32pe.cpp index 5ec608a3..d286f381 100644 --- a/src/p_w32pe.cpp +++ b/src/p_w32pe.cpp @@ -794,17 +794,17 @@ void PackW32Pe::pack(OutputFile *fo) ft.buf_len = ih.codesize; ft.addvalue = ih.codebase - rvamin; // compress - int strategy = allow_filter ? 0 : -3; + int filter_strategy = allow_filter ? 0 : -3; // disable filters for files with broken headers if (ih.codebase + ih.codesize > ph.u_len) { ft.buf_len = 1; - strategy = -3; + filter_strategy = -3; } - compressWithFilters(&ft, 2048, strategy, - NULL, NULL, ih.codebase, rvamin); + compressWithFilters(&ft, 2048, NULL_cconf, filter_strategy, + ih.codebase, rvamin); // info: see buildLoader() newvsize = (ph.u_len + rvamin + ph.overlap_overhead + oam1) &~ oam1; if (tlsindex && ((newvsize - ph.c_len - 1024 + oam1) &~ oam1) > tlsindex + 4) diff --git a/src/packer.cpp b/src/packer.cpp index a976a3d8..28b57b07 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -1142,7 +1142,7 @@ void Packer::relocateLoader() // - ibuf[] is restored to the original unfiltered version // - obuf[] contains the best compressed version // -// strategy: +// filter_strategy: // n: try the first N filters, use best one // -1: try all filters, use first working one // -2: try only the opt->filter filter @@ -1172,19 +1172,104 @@ void Packer::relocateLoader() // is OK because of the simplicity of not having two output arrays. **************************************************************************/ +static int prepareMethods(int *methods, int ph_method, const int *all_methods) +{ + int nmethods = 0; + if (!opt->all_methods || all_methods == NULL) + { + methods[nmethods++] = ph_method; + return nmethods; + } + for (int mm = 0; all_methods[mm] != M_END; ++mm) + { + int method = all_methods[mm]; + if (method == M_ULTRA_BRUTE && !opt->ultra_brute) + break; + if (method == M_SKIP || method == M_ULTRA_BRUTE) + continue; + if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(method)) + continue; + // use this method + assert(Packer::isValidCompressionMethod(method)); + methods[nmethods++] = method; + } + return nmethods; +} + + +static int prepareFilters(int *filters, int &filter_strategy, + const int *all_filters) +{ + int nfilters = 0; + + // setup filter filter_strategy + if (filter_strategy == 0) + { + if (opt->all_filters) + // choose best from all available filters + filter_strategy = INT_MAX; + else if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters)) + // try opt->filter + filter_strategy = -2; + else + // try the first working filter + filter_strategy = -1; + } + assert(filter_strategy != 0); + + if (filter_strategy == -3) + goto done; + if (filter_strategy == -2) + { + if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters)) + { + filters[nfilters++] = opt->filter; + goto done; + } + filter_strategy = -1; + } + assert(filter_strategy >= -1); + + const int *filter_list; + filter_list = all_filters; + while (filter_list && *filter_list != FT_END) + { + int filter_id = *filter_list++; + if (filter_id == FT_ULTRA_BRUTE && !opt->ultra_brute) + break; + if (filter_id == FT_SKIP || filter_id == FT_ULTRA_BRUTE) + continue; + if (filter_id == 0) + continue; + // use this filter + assert(Filter::isValidFilter(filter_id)); + filters[nfilters++] = filter_id; + if (filter_strategy >= 0 && nfilters >= filter_strategy) + break; + } + +done: + // filter_strategy now only means "stop after first successful filter" + filter_strategy = (filter_strategy < 0) ? -1 : 0; + // make sure that we have a "no filter" fallback + for (int i = 0; i < nfilters; i++) + if (filters[i] == 0) + return nfilters; + filters[nfilters++] = 0; + return nfilters; +} + + void Packer::compressWithFilters(Filter *parm_ft, const unsigned overlap_range, - int strategy, const int *parm_filters, const upx_compress_config_t *cconf, + int filter_strategy, unsigned filter_off, unsigned compress_buf_off, - unsigned char *hdr_buf, - unsigned hdr_u_len) + const upx_bytep hdr_buf, unsigned hdr_u_len) { - const int *f; - // + // struct copies const PackHeader orig_ph = this->ph; PackHeader best_ph = this->ph; - // const Filter orig_ft = *parm_ft; Filter best_ft = *parm_ft; // @@ -1201,109 +1286,42 @@ void Packer::compressWithFilters(Filter *parm_ft, assert(orig_ft.id == 0); assert(filter_off + filter_len <= compress_buf_off + compress_buf_len); - // setup filter strategy - if (strategy == 0) - { - if (opt->all_filters) - // choose best from all available filters - strategy = INT_MAX; - else if (opt->filter >= 0 && isValidFilter(opt->filter)) - // try opt->filter - strategy = -2; - else - // try the first working filter - strategy = -1; - } - assert(strategy != 0); + // prepare methods and filters + int methods[256]; + int nmethods = prepareMethods(methods, ph.method, getCompressionMethods(-1, ph.level)); + assert(nmethods > 0); assert(nmethods < 256); + int filters[256]; + int nfilters = prepareFilters(filters, filter_strategy, getFilters()); + assert(nfilters > 0); assert(nfilters < 256); +#if 1 + printf("compressWithFilters: m(%d):", nmethods); + for (int i = 0; i < nmethods; i++) printf(" %d", methods[i]); + printf(" f(%d):", nfilters); + for (int i = 0; i < nfilters; i++) printf(" %d", filters[i]); + printf("\n"); +#endif - // setup raw_filters - int tmp_filters[] = { 0, -1 }; - const int *raw_filters = NULL; - if (strategy == -3) - raw_filters = tmp_filters; - else if (strategy == -2 && opt->filter >= 0) - { - tmp_filters[0] = opt->filter; - raw_filters = tmp_filters; - } + // update total_passes; previous (ui_total_passes > 0) means incremental + if (uip->ui_total_passes > 0) + uip->ui_total_passes -= 1; + if (filter_strategy < 0) + uip->ui_total_passes += nmethods; else - { - raw_filters = parm_filters; - if (raw_filters == NULL) - raw_filters = getFilters(); - if (raw_filters == NULL) - raw_filters = tmp_filters; - } - - // first pass - count number of filters - int raw_nfilters = 0; - for (f = raw_filters; *f >= 0; f++) - { - assert(isValidFilter(*f)); - raw_nfilters++; - } - - // copy filters, add a 0 - int nfilters = 0; - bool zero_seen = false; - Array(int, filters, raw_nfilters + 2); - for (f = raw_filters; *f >= 0; f++) - { - if (*f == 0) - zero_seen = true; - filters[nfilters++] = *f; - if (nfilters == strategy) - break; - } - if (!zero_seen) - filters[nfilters++] = 0; - filters[nfilters] = -1; - - // methods - int tmp_methods[] = { ph.method, M_END }; - const int *methods = NULL; - if (opt->all_methods) - methods = getCompressionMethods(-1, ph.level); - if (methods == NULL) - methods = tmp_methods; - int nmethods = 0; - for (int mm = 0; methods[mm] != M_END; ++mm) - { - 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 && M_IS_LZMA(methods[mm])) - continue; - assert(isValidCompressionMethod(methods[mm])); - nmethods++; - } - assert(nmethods > 0); - - // update total_passes; previous (0 < ui_total_passes) means incremental - if (strategy < 0) - uip->ui_total_passes += 1 * nmethods - (0 < uip->ui_total_passes); - else - uip->ui_total_passes += nfilters * nmethods - (0 < uip->ui_total_passes); + uip->ui_total_passes += nfilters * nmethods; // Working buffer for compressed data. Don't waste memory. MemBuffer *otemp = &obuf; MemBuffer otemp_buf; - // compress - int nfilters_success = 0; - for (int mm = 0; methods[mm] != M_END; ++mm) // for all methods + // compress using all methods/filters + int nfilters_success_total = 0; + for (int mm = 0; mm < nmethods; mm++) // for all methods { - 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 && M_IS_LZMA(methods[mm])) - continue; + assert(isValidCompressionMethod(methods[mm])); unsigned hdr_c_len = 0; if (hdr_buf && hdr_u_len) { - if (nfilters_success != 0 && otemp == &obuf) + if (nfilters_success_total != 0 && otemp == &obuf) { // do not overwrite obuf otemp_buf.allocForCompression(compress_buf_len); @@ -1316,21 +1334,22 @@ void Packer::compressWithFilters(Filter *parm_ft, if (hdr_c_len >= hdr_u_len) throwInternalError("header compression size increase"); } - for (int i = 0; i < nfilters; i++) // for all filters + int nfilters_success_mm = 0; + for (int ff = 0; ff < nfilters; ff++) // for all filters { + assert(isValidFilter(filters[ff])); ibuf.checkState(); obuf.checkState(); // get fresh packheader ph = orig_ph; ph.method = methods[mm]; - ph.filter = filters[i]; + ph.filter = filters[ff]; ph.overlap_overhead = 0; // get fresh filter Filter ft = orig_ft; ft.init(ph.filter, orig_ft.addvalue); // filter optimizeFilter(&ft, ibuf + filter_off, filter_len); - bool success = ft.filter(ibuf + filter_off, filter_len); if (ft.id != 0 && ft.calls == 0) { @@ -1340,9 +1359,9 @@ void Packer::compressWithFilters(Filter *parm_ft, if (!success) { // filter failed or was useless - if (strategy > 0) + if (filter_strategy >= 0) { - // adjust passes + // adjust ui passes if (uip->ui_pass >= 0) uip->ui_pass++; } @@ -1353,12 +1372,13 @@ void Packer::compressWithFilters(Filter *parm_ft, printf("filter: id 0x%02x size %6d, calls %5d/%5d/%3d/%5d/%5d, cto 0x%02x\n", ft.id, ft.buf_len, ft.calls, ft.noncalls, ft.wrongcalls, ft.firstcall, ft.lastcall, ft.cto); #endif - if (nfilters_success != 0 && otemp == &obuf) + if (nfilters_success_total != 0 && otemp == &obuf) { otemp_buf.allocForCompression(compress_buf_len); otemp = &otemp_buf; } - nfilters_success++; + nfilters_success_total++; + nfilters_success_mm++; ph.filter_cto = ft.cto; ph.n_mru = ft.n_mru; // compress @@ -1413,13 +1433,14 @@ void Packer::compressWithFilters(Filter *parm_ft, obuf.checkState(); otemp->checkState(); // - if (strategy < 0) + if (filter_strategy < 0) break; } + assert(nfilters_success_mm > 0); } // postconditions 1) - assert(nfilters_success > 0); + assert(nfilters_success_total > 0); assert(best_ph.u_len == orig_ph.u_len); assert(best_ph.filter == best_ft.id); assert(best_ph.filter_cto == best_ft.cto); diff --git a/src/packer.h b/src/packer.h index 18c46b66..c25b23e6 100644 --- a/src/packer.h +++ b/src/packer.h @@ -180,12 +180,11 @@ protected: // high-level compression drivers void compressWithFilters(Filter *ft, const unsigned overlap_range, - int strategy = 0, - const int *filters = NULL, - const upx_compress_config_t *cconf = NULL, + const upx_compress_config_t *cconf, + int filter_strategy = 0, unsigned filter_buf_off = 0, unsigned compress_buf_off = 0, - unsigned char *header_buffer = 0, + const upx_bytep header_buffer = NULL, unsigned header_length = 0); // util for verifying overlapping decompresion diff --git a/src/packer_c.cpp b/src/packer_c.cpp index d0c0bd27..0bb4890d 100644 --- a/src/packer_c.cpp +++ b/src/packer_c.cpp @@ -53,25 +53,21 @@ const int *Packer::getDefaultCompressionMethods_8(int method, int level, int sma { #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_all[] = { 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_cl1b[] = { M_CL1B_8, M_END }; static const int m_lzma[] = { M_LZMA, M_END }; + static const int m_nrv2b[] = { M_NRV2B_8, M_END }; + static const int m_nrv2d[] = { M_NRV2D_8, M_END }; + static const int m_nrv2e[] = { M_NRV2E_8, M_END }; + if (method == -1) return m_all; + //if (M_IS_CL1B(method)) return m_cl1b; + if (M_IS_LZMA(method)) return m_lzma; + if (M_IS_NRV2B(method)) return m_nrv2b; + if (M_IS_NRV2D(method)) return m_nrv2d; + if (M_IS_NRV2E(method)) return m_nrv2e; if (small < 0) small = file_size <= 512*1024; - if (M_IS_NRV2B(method)) - return m_nrv2b; - if (M_IS_NRV2D(method)) - return m_nrv2d; - if (M_IS_NRV2E(method)) - return m_nrv2e; - if (M_IS_CL1B(method)) - return m_cl1b; - if (M_IS_LZMA(method)) - return m_lzma; - assert(method == -1); // --all-methods if (level == 1 || small) return m_nrv2b; return m_nrv2e; @@ -80,25 +76,21 @@ 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_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_all[] = { 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_cl1b[] = { M_CL1B_LE32, M_END }; static const int m_lzma[] = { M_LZMA, M_END }; + static const int m_nrv2b[] = { M_NRV2B_LE32, M_END }; + static const int m_nrv2d[] = { M_NRV2D_LE32, M_END }; + static const int m_nrv2e[] = { M_NRV2E_LE32, M_END }; + if (method == -1) return m_all; + //if (M_IS_CL1B(method)) return m_cl1b; + if (M_IS_LZMA(method)) return m_lzma; + if (M_IS_NRV2B(method)) return m_nrv2b; + if (M_IS_NRV2D(method)) return m_nrv2d; + if (M_IS_NRV2E(method)) return m_nrv2e; if (small < 0) small = file_size <= 512*1024; - if (M_IS_NRV2B(method)) - return m_nrv2b; - if (M_IS_NRV2D(method)) - return m_nrv2d; - if (M_IS_NRV2E(method)) - return m_nrv2e; - if (M_IS_CL1B(method)) - return m_cl1b; - if (M_IS_LZMA(method)) - return m_lzma; - assert(method == -1); // --all-methods if (level == 1 || small) return m_nrv2b; return m_nrv2e; @@ -135,6 +127,7 @@ const char *Packer::getDecompressorSections() const "N2EFAS10,+80CXXXX,N2EFAS11,N2EDEC10,N2EFAS20," "N2EDEC20,N2EFAS30,N2EDEC30,N2EFAS40,N2EFAS50," "N2EDEC50,N2EFAS60,+40CXXXX,N2EFAS61,N2EDEC60"; +#if 0 static const char cl1b_le32_small[] = "CL1ENTER,CL1SMA10,CL1RLOAD," "CL1WID01,CL1SMA1B," @@ -193,6 +186,7 @@ const char *Packer::getDecompressorSections() const "CL1LEN01,CL1FAS1B," "CL1LEN02," "CL1COPY0"; +#endif static const char lzma_small[] = "LZMA_DEC00,LZMA_DEC10,LZMA_DEC30"; static const char lzma_fast[] = @@ -208,8 +202,8 @@ const char *Packer::getDecompressorSections() const return opt->small ? nrv2d_le32_small : nrv2d_le32_fast; if (ph.method == M_NRV2E_LE32) 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_CL1B_LE32) +// return opt->small ? cl1b_le32_small : cl1b_le32_fast; if (M_IS_LZMA(ph.method)) { if (UPX_F_LINUX_ELF_i386 ==ph.format || UPX_F_LINUX_ELFI_i386 ==ph.format diff --git a/src/packer_f.cpp b/src/packer_f.cpp index f9290df2..52dc407b 100644 --- a/src/packer_f.cpp +++ b/src/packer_f.cpp @@ -37,16 +37,7 @@ bool Packer::isValidFilter(int filter_id) const { - if (!Filter::isValidFilter(filter_id)) - return false; - if (filter_id == 0) - return true; - for (const int *f = getFilters(); f && *f >= 0; f++) - { - if (*f == filter_id) - return true; - } - return false; + return Filter::isValidFilter(filter_id, getFilters()); } @@ -106,19 +97,19 @@ void Packer::scanFilters(Filter *ft, const upx_byte *buf, unsigned buf_len, #define FNOMRU 1 // filter, but not using mru #define MRUFLT 2 // mru filter -static inline unsigned f80_call(int fid) +static inline unsigned f80_call(int filter_id) { - return (1+ (0x0f & fid)) % 3; + return (1+ (0x0f & filter_id)) % 3; } -static inline unsigned f80_jmp1(int fid) +static inline unsigned f80_jmp1(int filter_id) { - return ((1+ (0x0f & fid)) / 3) % 3; + return ((1+ (0x0f & filter_id)) / 3) % 3; } -static inline unsigned f80_jcc2(int fid) +static inline unsigned f80_jcc2(int filter_id) { - return f80_jmp1(fid); + return f80_jmp1(filter_id); }