src: refactoring: create packhead.h and move some methods

This commit is contained in:
Markus F.X.J. Oberhumer 2023-08-11 03:57:20 +02:00
parent c65c882ecc
commit 777d4f5279
7 changed files with 217 additions and 174 deletions

View File

@ -1493,7 +1493,7 @@ PackLinuxElf32::buildLinuxLoader(
h.sz_cpr = mb_cprLoader.getSize(); // max that upx_compress may use
{
int r = upx_compress(uncLoader, sz_unc, sizeof(h) + cprLoader, &sz_cpr,
nullptr, forced_method(method), 10, nullptr, nullptr );
nullptr, ph_forced_method(method), 10, nullptr, nullptr );
h.sz_cpr = sz_cpr; // actual length used
if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc)
throwInternalError("loader compression failed");
@ -1514,7 +1514,7 @@ PackLinuxElf32::buildLinuxLoader(
}
else {
addStubEntrySections(ft, (methods_used ? methods_used
: (1u << forced_method(ph.method))) );
: (1u << ph_forced_method(ph.method))) );
if (!xct_off) {
defineSymbols(ft);
}
@ -1599,7 +1599,7 @@ PackLinuxElf64::buildLinuxLoader(
h.sz_cpr = mb_cprLoader.getSize(); // max that upx_compress may use
{
int r = upx_compress(uncLoader, sz_unc, sizeof(h) + cprLoader, &sz_cpr,
nullptr, forced_method(method), 10, nullptr, nullptr );
nullptr, ph_forced_method(method), 10, nullptr, nullptr );
h.sz_cpr = sz_cpr; // actual length used
if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc)
throwInternalError("loader compression failed");
@ -1620,7 +1620,7 @@ PackLinuxElf64::buildLinuxLoader(
}
else {
addStubEntrySections(ft, (methods_used ? methods_used
: (1u << forced_method(ph.method))) );
: (1u << ph_forced_method(ph.method))) );
if (!xct_off) {
defineSymbols(ft);
}
@ -3900,7 +3900,7 @@ void PackLinuxElf32::pack1(OutputFile * /*fo*/, Filter &ft)
fi->readx(ibuf, filesz);
ft = orig_ft;
ph = orig_ph;
ph.method = force_method(methods[k]);
ph.method = ph_force_method(methods[k]);
ph.u_len = filesz;
compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true);
sz_this += ph.c_len;
@ -3913,7 +3913,7 @@ void PackLinuxElf32::pack1(OutputFile * /*fo*/, Filter &ft)
fi->readx(ibuf, sz_tail);
ft = orig_ft;
ph = orig_ph;
ph.method = force_method(methods[k]);
ph.method = ph_force_method(methods[k]);
ph.u_len = sz_tail;
compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true);
sz_this += ph.c_len;
@ -3926,7 +3926,7 @@ void PackLinuxElf32::pack1(OutputFile * /*fo*/, Filter &ft)
}
ft = orig_ft;
ph = orig_ph;
ph.method = force_method(method_best);
ph.method = ph_force_method(method_best);
}
note_size = 0;
@ -4782,7 +4782,7 @@ void PackLinuxElf64::pack1(OutputFile * /*fo*/, Filter &ft)
fi->readx(ibuf, filesz);
ft = orig_ft;
ph = orig_ph;
ph.method = force_method(methods[k]);
ph.method = ph_force_method(methods[k]);
ph.u_len = filesz;
compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true);
sz_this += ph.c_len;
@ -4795,7 +4795,7 @@ void PackLinuxElf64::pack1(OutputFile * /*fo*/, Filter &ft)
fi->readx(ibuf, sz_tail);
ft = orig_ft;
ph = orig_ph;
ph.method = force_method(methods[k]);
ph.method = ph_force_method(methods[k]);
ph.u_len = sz_tail;
compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true);
sz_this += ph.c_len;
@ -4808,7 +4808,7 @@ void PackLinuxElf64::pack1(OutputFile * /*fo*/, Filter &ft)
}
ft = orig_ft;
ph = orig_ph;
ph.method = force_method(method_best);
ph.method = ph_force_method(method_best);
}
note_size = 0;

View File

@ -406,7 +406,7 @@ void PackUnix::packExtent(
MemBuffer hdr_obuf;
hdr_obuf.allocForCompression(hdr_u_len);
int r = upx_compress(hdr_ibuf, hdr_u_len, hdr_obuf, &hdr_c_len, nullptr,
forced_method(ph.method), 10, nullptr, nullptr);
ph_forced_method(ph.method), 10, nullptr, nullptr);
if (r != UPX_E_OK)
throwInternalError("header compression failed");
if (hdr_c_len >= hdr_u_len)
@ -419,7 +419,7 @@ void PackUnix::packExtent(
memset(&tmp, 0, sizeof(tmp));
set_te32(&tmp.sz_unc, hdr_u_len);
set_te32(&tmp.sz_cpr, hdr_c_len);
tmp.b_method = (unsigned char) forced_method(ph.method);
tmp.b_method = (unsigned char) ph_forced_method(ph.method);
tmp.b_extra = b_extra;
fo->write(&tmp, sizeof(tmp));
total_out += sizeof(tmp);

View File

@ -149,34 +149,6 @@ bool Packer::testUnpackFormat(int format) const {
return canUnpackFormat(format);
}
bool ph_skipVerify(const PackHeader &ph) noexcept {
if (M_IS_DEFLATE(ph.method))
return false;
if (M_IS_LZMA(ph.method))
return false;
if (ph.level > 1)
return false;
return true;
}
int force_method(int method) noexcept // mark as forced
{
return (0x80ul << 24) | method;
}
int is_forced_method(int method) noexcept // predicate
{
return -0x80 == (method >> 24);
}
int forced_method(int method) noexcept // extract the forced method
{
if (is_forced_method(method))
method &= ~(0x80ul << 24);
assert_noexcept(method > 0);
return method;
}
/*************************************************************************
// compress - wrap call to low-level upx_compress()
**************************************************************************/
@ -203,7 +175,7 @@ bool Packer::compress(SPAN_P(byte) i_ptr, unsigned i_len, SPAN_P(byte) o_ptr,
if (cconf_parm)
cconf = *cconf_parm;
// cconf options
int method = forced_method(ph.method);
int method = ph_forced_method(ph.method);
if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method)) {
if (opt->crp.crp_ucl.c_flags != -1)
cconf.conf_ucl.c_flags = opt->crp.crp_ucl.c_flags;
@ -332,39 +304,6 @@ bool Packer::checkFinalCompressionRatio(const OutputFile *fo) const {
// decompress
**************************************************************************/
void ph_decompress(PackHeader &ph, SPAN_P(const byte) in, SPAN_P(byte) out, bool verify_checksum,
Filter *ft) {
unsigned adler;
// verify checksum of compressed data
if (verify_checksum) {
adler = upx_adler32(raw_bytes(in, ph.c_len), ph.c_len, ph.saved_c_adler);
if (adler != ph.c_adler)
throwChecksumError();
}
// decompress
if (ph.u_len < ph.c_len) {
throwCantUnpack("header corrupted");
}
unsigned new_len = ph.u_len;
int r = upx_decompress(raw_bytes(in, ph.c_len), ph.c_len, raw_bytes(out, ph.u_len), &new_len,
forced_method(ph.method), &ph.compress_result);
if (r == UPX_E_OUT_OF_MEMORY)
throwOutOfMemoryException();
if (r != UPX_E_OK || new_len != ph.u_len)
throwCompressedDataViolation();
// verify checksum of decompressed data
if (verify_checksum) {
if (ft)
ft->unfilter(raw_bytes(out, ph.u_len), ph.u_len);
adler = upx_adler32(raw_bytes(out, ph.u_len), ph.u_len, ph.saved_u_adler);
if (adler != ph.u_adler)
throwChecksumError();
}
}
void Packer::decompress(SPAN_P(const byte) in, SPAN_P(byte) out, bool verify_checksum, Filter *ft) {
ph_decompress(ph, in, out, verify_checksum, ft);
}
@ -373,33 +312,6 @@ void Packer::decompress(SPAN_P(const byte) in, SPAN_P(byte) out, bool verify_che
// overlapping decompression
**************************************************************************/
static bool ph_testOverlappingDecompression(const PackHeader &ph, const byte *buf, const byte *tbuf,
unsigned overlap_overhead) {
if (ph.c_len >= ph.u_len)
return false;
assert((int) overlap_overhead >= 0);
assert((int) (ph.u_len + overlap_overhead) >= 0);
// Because upx_test_overlap() does not use the asm_fast decompressor
// we must account for extra 3 bytes that asm_fast does use,
// or else we may fail at runtime decompression.
unsigned extra = 0;
if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method))
extra = 3;
if (overlap_overhead <= 4 + extra) // don't waste time here
return false;
overlap_overhead -= extra;
unsigned src_off = ph.u_len + overlap_overhead - ph.c_len;
unsigned new_len = ph.u_len;
int r = upx_test_overlap(buf - src_off, tbuf, src_off, ph.c_len, &new_len,
forced_method(ph.method), &ph.compress_result);
if (r == UPX_E_OUT_OF_MEMORY)
throwOutOfMemoryException();
return (r == UPX_E_OK && new_len == ph.u_len);
}
bool Packer::testOverlappingDecompression(const byte *buf, const byte *tbuf,
unsigned overlap_overhead) const {
return ph_testOverlappingDecompression(ph, buf, tbuf, overlap_overhead);
@ -1020,7 +932,7 @@ void Packer::relocateLoader() {
int Packer::prepareMethods(int *methods, int ph_method, const int *all_methods) const {
int nmethods = 0;
if (!opt->all_methods || all_methods == nullptr || (-0x80 == (ph_method >> 24))) {
methods[nmethods++] = forced_method(ph_method);
methods[nmethods++] = ph_forced_method(ph_method);
return nmethods;
}
for (int mm = 0; all_methods[mm] != M_END; ++mm) {
@ -1166,7 +1078,7 @@ void Packer::compressWithFilters(byte *i_ptr,
#endif
// update total_passes; previous (ui_total_passes > 0) means incremental
if (!is_forced_method(ph.method)) {
if (!ph_is_forced_method(ph.method)) {
if (uip->ui_total_passes > 0)
uip->ui_total_passes -= 1;
if (filter_strategy < 0)

View File

@ -27,77 +27,14 @@
#pragma once
#include "packhead.h"
#include "util/membuffer.h"
class InputFile;
class OutputFile;
class PackerBase;
class Packer;
class UiPacker;
class Filter;
/*************************************************************************
// PackHeader
// also see stub/src/include/header.S
**************************************************************************/
class PackHeader final {
friend class PackerBase;
friend class Packer;
// these are strictly private to friends PackerBase and Packer
explicit PackHeader() noexcept;
void putPackHeader(SPAN_S(byte) p);
bool decodePackHeaderFromBuf(SPAN_S(const byte) b, int blen);
public:
int getPackHeaderSize() const;
public:
// fields stored in compressed file
// enum { magic = UPX_MAGIC_LE32 };
int version;
int format; // executable format
int method; // compresison method
int level; // compresison level 1..10
unsigned u_len;
unsigned c_len;
unsigned u_adler;
unsigned c_adler;
unsigned u_file_size;
int filter;
int filter_cto;
int n_mru; // FIXME: rename to filter_misc
int header_checksum;
// support fields for verifying decompression
unsigned saved_u_adler;
unsigned saved_c_adler;
// info fields set by decodePackHeaderFromBuf()
unsigned buf_offset;
// info fields set by Packer::compress()
upx_compress_result_t compress_result;
// unsigned min_offset_found;
unsigned max_offset_found;
// unsigned min_match_found;
unsigned max_match_found;
// unsigned min_run_found;
unsigned max_run_found;
unsigned first_offset_found;
// unsigned same_match_offsets_found;
// info fields set by Packer::compressWithFilters()
unsigned overlap_overhead;
};
bool ph_skipVerify(const PackHeader &ph) noexcept;
void ph_decompress(PackHeader &ph, SPAN_P(const byte) in, SPAN_P(byte) out, bool verify_checksum,
Filter *ft);
bool ph_testOverlappingDecompression(const PackHeader &ph, SPAN_P(const byte) buf,
unsigned overlap_overhead);
/*************************************************************************
// purely abstract minimal base class for all packers
//
@ -388,8 +325,4 @@ private:
Packer &operator=(Packer &&) noexcept DELETED_FUNCTION;
};
int force_method(int method) noexcept; // (0x80ul<<24)|method
int forced_method(int method) noexcept; // (0x80ul<<24)|method ==> method
int is_forced_method(int method) noexcept; // predicate
/* vim:set ts=4 sw=4 et: */

View File

@ -210,7 +210,7 @@ const char *Packer::getDecompressorSections() const
static const char lzma_elf_fast[] =
"LZMA_ELF00,LZMA_DEC20,LZMA_DEC30";
unsigned const method = forced_method(ph.method);
unsigned const method = ph_forced_method(ph.method);
if (method == M_NRV2B_LE32)
return opt->small ? nrv2b_le32_small : nrv2b_le32_fast;
if (method == M_NRV2D_LE32)

View File

@ -26,7 +26,8 @@
*/
#include "conf.h"
#include "packer.h"
#include "packhead.h"
#include "filter.h" // for ft->unfilter()
/*************************************************************************
// PackHeader
@ -92,7 +93,7 @@ int PackHeader::getPackHeaderSize() const {
// see stub/header.ash
**************************************************************************/
void PackHeader::putPackHeader(SPAN_S(byte) p) {
void PackHeader::putPackHeader(SPAN_S(byte) p) const {
// NOTE: It is the caller's responsbility to ensure the buffer p has
// sufficient space for the header.
assert(get_le32(p) == UPX_MAGIC_LE32);
@ -277,4 +278,102 @@ bool PackHeader::decodePackHeaderFromBuf(SPAN_S(const byte) buf, int blen) {
return true;
}
/*************************************************************************
// ph method util
**************************************************************************/
bool ph_is_forced_method(int method) noexcept // predicate
{
return (method >> 24) == -0x80;
}
int ph_force_method(int method) noexcept // mark as forced
{
return method | (0x80u << 24);
}
int ph_forced_method(int method) noexcept // extract the forced method
{
if (ph_is_forced_method(method))
method &= ~(0x80u << 24);
assert_noexcept(method > 0);
return method;
}
bool ph_skipVerify(const PackHeader &ph) noexcept {
if (M_IS_DEFLATE(ph.method))
return false;
if (M_IS_LZMA(ph.method))
return false;
if (ph.level > 1)
return false;
return true;
}
/*************************************************************************
// ph decompress util
**************************************************************************/
void ph_decompress(PackHeader &ph, SPAN_P(const byte) in, SPAN_P(byte) out, bool verify_checksum,
Filter *ft) {
// verify checksum of compressed data
if (verify_checksum) {
unsigned adler = upx_adler32(raw_bytes(in, ph.c_len), ph.c_len, ph.saved_c_adler);
if (adler != ph.c_adler)
throwChecksumError();
}
// decompress
if (ph.u_len < ph.c_len)
throwCantUnpack("header corrupted");
unsigned new_len = ph.u_len;
int r = upx_decompress(raw_bytes(in, ph.c_len), ph.c_len, raw_bytes(out, ph.u_len), &new_len,
ph_forced_method(ph.method), &ph.compress_result);
if (r == UPX_E_OUT_OF_MEMORY)
throwOutOfMemoryException();
if (r != UPX_E_OK || new_len != ph.u_len)
throwCompressedDataViolation();
// verify checksum of decompressed data
if (verify_checksum) {
if (ft)
ft->unfilter(out, ph.u_len);
unsigned adler = upx_adler32(raw_bytes(out, ph.u_len), ph.u_len, ph.saved_u_adler);
if (adler != ph.u_adler)
throwChecksumError();
}
}
/*************************************************************************
// ph overlapping decompression util
**************************************************************************/
bool ph_testOverlappingDecompression(const PackHeader &ph, const byte *buf, const byte *tbuf,
unsigned overlap_overhead) {
if (ph.c_len >= ph.u_len)
return false;
assert((int) overlap_overhead >= 0);
assert((int) (ph.u_len + overlap_overhead) >= 0);
const int method = ph_forced_method(ph.method);
// Because upx_test_overlap() does not use the asm_fast decompressor
// we must account for extra 3 bytes that asm_fast does use,
// or else we may fail at runtime decompression.
unsigned extra = 0;
if (M_IS_NRV2B(method) || M_IS_NRV2D(method) || M_IS_NRV2E(method))
extra = 3;
if (overlap_overhead <= 4 + extra) // don't waste time here
return false;
overlap_overhead -= extra;
unsigned src_off = ph.u_len + overlap_overhead - ph.c_len;
unsigned new_len = ph.u_len;
int r = upx_test_overlap(buf - src_off, tbuf, src_off, ph.c_len, &new_len, method,
&ph.compress_result);
if (r == UPX_E_OUT_OF_MEMORY)
throwOutOfMemoryException();
return (r == UPX_E_OK && new_len == ph.u_len);
}
/* vim:set ts=4 sw=4 et: */

99
src/packhead.h Normal file
View File

@ -0,0 +1,99 @@
/* packhead.h --
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2023 Laszlo Molnar
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
<markus@oberhumer.com> <ezerotven+github@gmail.com>
*/
#pragma once
class Filter;
/*************************************************************************
// PackHeader
// also see stub/src/include/header.S
**************************************************************************/
class PackHeader final {
public:
explicit PackHeader() noexcept;
~PackHeader() noexcept = default;
void putPackHeader(SPAN_S(byte) p) const;
bool decodePackHeaderFromBuf(SPAN_S(const byte) b, int blen);
int getPackHeaderSize() const;
// fields stored in compressed file => see header.S
// enum { magic = UPX_MAGIC_LE32 };
int version;
int format; // executable format
int method; // compresison method
int level; // compresison level 1..10
unsigned u_len;
unsigned c_len;
unsigned u_adler;
unsigned c_adler;
unsigned u_file_size;
int filter;
int filter_cto;
int n_mru; // FIXME: rename to filter_misc
int header_checksum;
// support fields for verifying decompression
unsigned saved_u_adler;
unsigned saved_c_adler;
// info fields set by decodePackHeaderFromBuf()
unsigned buf_offset;
// info fields set by Packer::compress()
upx_compress_result_t compress_result;
// unsigned min_offset_found;
unsigned max_offset_found;
// unsigned min_match_found;
unsigned max_match_found;
// unsigned min_run_found;
unsigned max_run_found;
unsigned first_offset_found;
// unsigned same_match_offsets_found;
// info fields set by Packer::compressWithFilters()
unsigned overlap_overhead;
};
/*************************************************************************
// ph default util functions
**************************************************************************/
bool ph_is_forced_method(int method) noexcept; // predicate
int ph_force_method(int method) noexcept; // (0x80ul<<24)|method
int ph_forced_method(int method) noexcept; // (0x80ul<<24)|method ==> method
bool ph_skipVerify(const PackHeader &ph) noexcept;
void ph_decompress(PackHeader &ph, SPAN_P(const byte) in, SPAN_P(byte) out, bool verify_checksum,
Filter *ft);
bool ph_testOverlappingDecompression(const PackHeader &ph, const byte *buf, const byte *tbuf,
unsigned overlap_overhead);