mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
Extra parameter for compressWithFilters and packExtent,
to fix 2-pass problem with --brute on linux/elf386. Only one decompression method is allowed, chosen by smallest output for .text; but Elf headers come first. packer.cpp packer.h p_unix.cpp p_unix.h p_lx_elf.cpp committer: jreiser <jreiser> 1140241030 +0000
This commit is contained in:
parent
d3bcba6a05
commit
268e322e1c
|
@ -738,14 +738,7 @@ void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
|
|||
unsigned total_in = 0;
|
||||
unsigned total_out = 0;
|
||||
|
||||
ui_pass = -1; // Compressing Elf headers is invisible to UI.
|
||||
x.offset = 0;
|
||||
x.size = sizeof(Elf32_Ehdr) + sz_phdrs;
|
||||
{
|
||||
int const old_level = ph.level; ph.level = 10;
|
||||
packExtent(x, total_in, total_out, 0, fo);
|
||||
ph.level = old_level;
|
||||
}
|
||||
unsigned hdr_ulen = sizeof(Elf32_Ehdr) + sz_phdrs;
|
||||
|
||||
ui_pass = 0;
|
||||
ft.addvalue = 0;
|
||||
|
@ -770,7 +763,8 @@ void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
|
|||
// sometimes marks as PF_X anyway. So filter only first segment.
|
||||
packExtent(x, total_in, total_out,
|
||||
((0==nx && (Elf32_Phdr::PF_X & get_native32(&phdri[k].p_flags)))
|
||||
? &ft : 0 ), fo );
|
||||
? &ft : 0 ), fo, hdr_ulen);
|
||||
hdr_ulen = 0;
|
||||
++nx;
|
||||
}
|
||||
if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole?
|
||||
|
@ -819,14 +813,7 @@ void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
|
|||
unsigned total_in = 0;
|
||||
unsigned total_out = 0;
|
||||
|
||||
ui_pass = -1; // Compressing Elf headers is invisible to UI.
|
||||
x.offset = 0;
|
||||
x.size = sizeof(Elf64_Ehdr) + sz_phdrs;
|
||||
{
|
||||
int const old_level = ph.level; ph.level = 10;
|
||||
packExtent(x, total_in, total_out, 0, fo);
|
||||
ph.level = old_level;
|
||||
}
|
||||
unsigned hdr_ulen = sizeof(Elf64_Ehdr) + sz_phdrs;
|
||||
|
||||
ui_pass = 0;
|
||||
ft.addvalue = 0;
|
||||
|
@ -851,7 +838,8 @@ void PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
|
|||
// sometimes marks as PF_X anyway. So filter only first segment.
|
||||
packExtent(x, total_in, total_out,
|
||||
((0==nx && (Elf64_Phdr::PF_X & get_native64(&phdri[k].p_flags)))
|
||||
? &ft : 0 ), fo );
|
||||
? &ft : 0 ), fo, hdr_ulen);
|
||||
hdr_ulen = 0;
|
||||
++nx;
|
||||
}
|
||||
if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole?
|
||||
|
@ -1513,14 +1501,7 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft)
|
|||
unsigned total_in = 0;
|
||||
unsigned total_out = 0;
|
||||
|
||||
ui_pass = -1; // Compressing Elf headers is invisible to UI.
|
||||
x.offset = 0;
|
||||
x.size = sizeof(Elf32_Ehdr) + sz_phdrs;
|
||||
{
|
||||
int const old_level = ph.level; ph.level = 10;
|
||||
packExtent(x, total_in, total_out, 0, fo);
|
||||
ph.level = old_level;
|
||||
}
|
||||
unsigned hdr_ulen = sizeof(Elf32_Ehdr) + sz_phdrs;
|
||||
|
||||
ui_pass = 0;
|
||||
ft.addvalue = 0;
|
||||
|
@ -1542,7 +1523,8 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft)
|
|||
}
|
||||
packExtent(x, total_in, total_out,
|
||||
((Elf32_Phdr::PF_X & phdri[k].p_flags)
|
||||
? &ft : 0 ), fo );
|
||||
? &ft : 0 ), fo, hdr_ulen);
|
||||
hdr_ulen = 0;
|
||||
++nx;
|
||||
}
|
||||
if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole?
|
||||
|
|
|
@ -304,9 +304,16 @@ void PackUnix::packExtent(
|
|||
unsigned &total_in,
|
||||
unsigned &total_out,
|
||||
Filter *ft,
|
||||
OutputFile *fo
|
||||
OutputFile *fo,
|
||||
unsigned hdr_ulen
|
||||
)
|
||||
{
|
||||
MemBuffer hdr_ibuf;
|
||||
if (hdr_ulen) {
|
||||
hdr_ibuf.alloc(hdr_ulen);
|
||||
fi->seek(0, SEEK_SET);
|
||||
int l = fi->readx(hdr_ibuf, hdr_ulen);
|
||||
}
|
||||
fi->seek(x.offset, SEEK_SET);
|
||||
for (off_t rest = x.size; 0 != rest; ) {
|
||||
int const strategy = getStrategy(*ft);
|
||||
|
@ -336,7 +343,9 @@ void PackUnix::packExtent(
|
|||
ft->id = 0;
|
||||
ft->cto = 0;
|
||||
|
||||
compressWithFilters(ft, OVERHEAD, strategy);
|
||||
compressWithFilters(ft, OVERHEAD, strategy,
|
||||
NULL, 0, 0, 0, 0, // those 5 args are the defaults
|
||||
hdr_ibuf, hdr_ulen);
|
||||
}
|
||||
else {
|
||||
(void) compress(ibuf, obuf); // ignore return value
|
||||
|
@ -358,6 +367,24 @@ void PackUnix::packExtent(
|
|||
|
||||
// write block sizes
|
||||
b_info tmp;
|
||||
if (hdr_ulen) {
|
||||
unsigned hdr_clen;
|
||||
MemBuffer hdr_obuf;
|
||||
unsigned result[16];
|
||||
upx_compress_config_t conf;
|
||||
memset(&conf, 0xff, sizeof(conf));
|
||||
hdr_obuf.allocForCompression(hdr_ulen);
|
||||
int r = upx_compress(hdr_ibuf, hdr_ulen, hdr_obuf, &hdr_clen, 0,
|
||||
ph.method, 10, &conf, result);
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
set_native32(&tmp.sz_unc, hdr_ulen);
|
||||
set_native32(&tmp.sz_cpr, hdr_clen);
|
||||
tmp.b_method = (unsigned char) ph.method;
|
||||
fo->write(&tmp, sizeof(tmp));
|
||||
b_len += sizeof(b_info);
|
||||
fo->write(hdr_obuf, hdr_clen);
|
||||
hdr_ulen = 0; // compress hdr one time only
|
||||
}
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
set_native32(&tmp.sz_unc, ph.u_len);
|
||||
set_native32(&tmp.sz_cpr, ph.c_len);
|
||||
|
|
|
@ -81,7 +81,8 @@ protected:
|
|||
off_t size;
|
||||
};
|
||||
virtual void packExtent(const Extent &x,
|
||||
unsigned &total_in, unsigned &total_out, Filter *, OutputFile *);
|
||||
unsigned &total_in, unsigned &total_out, Filter *, OutputFile *,
|
||||
unsigned hdr_len = 0);
|
||||
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
|
||||
unsigned &total_in, unsigned &total_out,
|
||||
unsigned &c_adler, unsigned &u_adler,
|
||||
|
|
|
@ -1258,13 +1258,32 @@ const char *Packer::getDecompressor() const
|
|||
// executable formats.
|
||||
//
|
||||
// It will replace the tryFilters() / compress() call sequence.
|
||||
|
||||
// 2006-02-15: hdr_buf and hdr_u_len are default empty input "header" array
|
||||
// to fix a 2-pass problem with Elf headers. As of today there can be
|
||||
// only one decompression method per executable output file, and that method
|
||||
// is the one that gives best compression for .text and loader. However,
|
||||
// the Elf headers precede .text in the output file, and are written first.
|
||||
// "--brute" compression often compressed the Elf headers using nrv2b
|
||||
// but the .text (and loader) with nrv2e. This often resulted in SIGSEGV
|
||||
// during decompression.
|
||||
// The workaround is for hdr_buf and hdr_u_len to describe the Elf headers
|
||||
// (typically less than 512 bytes) when .text is passed in, and include
|
||||
// them in the calculation of shortest output. Then the result
|
||||
// this->ph.method will say which [single] method to use for everthing.
|
||||
// The Elf headers are never filtered. They are short enough (< 512 bytes)
|
||||
// that compressing them more than once per method (once here when choosing,
|
||||
// once again just before writing [because compressWithFilters discards])
|
||||
// is OK because of the simplicity of not having two output arrays.
|
||||
**************************************************************************/
|
||||
|
||||
void Packer::compressWithFilters(Filter *parm_ft,
|
||||
const unsigned overlap_range,
|
||||
int strategy, const int *parm_filters,
|
||||
unsigned max_offset, unsigned max_match,
|
||||
unsigned filter_off, unsigned compress_buf_off)
|
||||
unsigned filter_off, unsigned compress_buf_off,
|
||||
unsigned char *hdr_buf,
|
||||
unsigned hdr_u_len)
|
||||
{
|
||||
const int *f;
|
||||
//
|
||||
|
@ -1280,6 +1299,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
best_ph.c_len = orig_ph.u_len;
|
||||
best_ph.overlap_overhead = 0;
|
||||
unsigned best_ph_lsize = 0;
|
||||
unsigned best_hdr_clen = 0;
|
||||
|
||||
// preconditions
|
||||
assert(orig_ph.filter == 0);
|
||||
|
@ -1373,6 +1393,14 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
int nfilters_success = 0;
|
||||
for (int m = 0; m < nmethods; m++) // for all methods
|
||||
{
|
||||
unsigned hdr_clen = 0;
|
||||
if (hdr_buf && hdr_u_len) {
|
||||
unsigned result[16];
|
||||
upx_compress_config_t conf;
|
||||
memset(&conf, 0xff, sizeof(conf));
|
||||
int r = upx_compress(hdr_buf, hdr_u_len, obuf, &hdr_clen,
|
||||
0, methods[m], 10, &conf, result);
|
||||
}
|
||||
for (int i = 0; i < nfilters; i++) // for all filters
|
||||
{
|
||||
ibuf.checkState();
|
||||
|
@ -1428,19 +1456,19 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
lsize = buildLoader(&ft);
|
||||
}
|
||||
#if 0
|
||||
printf("\n%2d %02x: %d +%4d = %d (best: %d +%4d = %d)\n", ph.method, ph.filter,
|
||||
ph.c_len, lsize, ph.c_len + lsize,
|
||||
best_ph.c_len, best_ph_lsize, best_ph.c_len + best_ph_lsize);
|
||||
printf("\n%2d %02x: %d +%4d +%3d = %d (best: %d +%4d +%3d = %d)\n", ph.method, ph.filter,
|
||||
ph.c_len, lsize, hdr_clen, ph.c_len + lsize + hdr_clen,
|
||||
best_ph.c_len, best_ph_lsize, best_hdr_clen, best_ph.c_len + best_ph_lsize + best_hdr_clen);
|
||||
#endif
|
||||
bool update = false;
|
||||
if (ph.c_len + lsize < best_ph.c_len + best_ph_lsize)
|
||||
if (ph.c_len + lsize + hdr_clen < best_ph.c_len + best_ph_lsize + best_hdr_clen)
|
||||
update = true;
|
||||
else if (ph.c_len + lsize == best_ph.c_len + best_ph_lsize)
|
||||
else if (ph.c_len + lsize + hdr_clen == best_ph.c_len + best_ph_lsize + best_hdr_clen)
|
||||
{
|
||||
// prefer smaller loaders
|
||||
if (lsize < best_ph_lsize)
|
||||
if (lsize + hdr_clen < best_ph_lsize + best_hdr_clen)
|
||||
update = true;
|
||||
else if (lsize == best_ph_lsize)
|
||||
else if (lsize + hdr_clen == best_ph_lsize + best_hdr_clen)
|
||||
{
|
||||
// prefer less overlap_overhead
|
||||
if (ph.overlap_overhead < best_ph.overlap_overhead)
|
||||
|
@ -1455,6 +1483,7 @@ void Packer::compressWithFilters(Filter *parm_ft,
|
|||
// save compression results
|
||||
best_ph = ph;
|
||||
best_ph_lsize = lsize;
|
||||
best_hdr_clen = hdr_clen;
|
||||
best_ft = ft;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,7 +172,9 @@ protected:
|
|||
const int *filters = NULL,
|
||||
unsigned max_offset = 0, unsigned max_match = 0,
|
||||
unsigned filter_buf_off = 0,
|
||||
unsigned compress_buf_off = 0);
|
||||
unsigned compress_buf_off = 0,
|
||||
unsigned char *header_buffer = 0,
|
||||
unsigned header_length = 0);
|
||||
|
||||
// util for verifying overlapping decompresion
|
||||
// non-destructive test
|
||||
|
|
Loading…
Reference in New Issue
Block a user