Coverage Report

Created: 2026-09-01 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/upx/src/packer.h
Line
Count
Source
1
/* packer.h --
2
3
   This file is part of the UPX executable compressor.
4
5
   Copyright (C) Markus Franz Xaver Johannes Oberhumer
6
   Copyright (C) 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
#pragma once
29
30
#include "packhead.h"
31
#include "util/membuffer.h"
32
33
class InputFile;
34
class OutputFile;
35
class UiPacker;
36
class Filter;
37
38
/*************************************************************************
39
// PackerBase: abstract minimal base class for all packers
40
//
41
// clients: PackMaster, UiPacker
42
**************************************************************************/
43
44
class PackerBase /*not_final*/ {
45
    friend class UiPacker;
46
protected:
47
    explicit PackerBase(InputFile *f);
48
public:
49
462k
    virtual ~PackerBase() noexcept {}
50
    // getVersion() enables detecting forward incompatibility of unpack()
51
    //   by old UPX when newer UPX changes the format of compressed output.
52
    virtual int getVersion() const = 0;
53
    // A unique integer ID for this executable format; see UPX_F_xxx in conf.h.
54
    virtual int getFormat() const = 0;
55
    virtual const char *getName() const = 0;
56
    virtual const char *getFullName(const Options *) const = 0;
57
    virtual const int *getCompressionMethods(int method, int level) const = 0;
58
    virtual const int *getFilters() const = 0;
59
60
    // canPack() should throw a cantPackException explaining why it cannot pack
61
    //   a recognized format.
62
    // canPack() can also return -1 to fail early; see class PackMaster
63
    virtual tribool canPack() = 0;
64
    // canUnpack() should throw a cantUnpackException explaining why it cannot unpack
65
    //   a recognized format.
66
    // canUnpack() can also return -1 to fail early; see class PackMaster
67
    virtual tribool canUnpack() = 0;
68
69
    // PackMaster entries
70
    virtual void assertPacker() const = 0;
71
    virtual void initPackHeader() = 0;
72
    virtual void updatePackHeader() = 0;
73
    virtual void doPack(OutputFile *fo) = 0;
74
    virtual void doUnpack(OutputFile *fo) = 0;
75
    virtual void doTest() = 0;
76
    virtual void doList() = 0;
77
    virtual void doFileInfo() = 0;
78
79
    // arbitrary limits, increase as needed
80
    static constexpr unsigned MAX_METHODS = 8;  // for getCompressionMethods()
81
    static constexpr unsigned MAX_FILTERS = 16; // for getFilters()
82
83
protected:
84
    InputFile *const fi; // reference
85
    // multiple names for "file_size" to avoid casts; limited by UPX_RSIZE_MAX
86
    union {                          // unnamed union
87
        const upx_int64_t file_size; // must get set by constructor
88
        const upx_uint64_t file_size_u;
89
        const upx_int64_t file_size_i64;
90
        const upx_uint64_t file_size_u64;
91
    };
92
    union { // unnamed union
93
        const upx_int32_t file_size_i32;
94
        const upx_uint32_t file_size_u32;
95
    };
96
    PackHeader ph; // must be filled by canUnpack(); also used by UiPacker
97
};
98
99
/*************************************************************************
100
// Packer: default implementation base class for all current packers
101
//
102
// Packer can be viewed as "PackerDefaultImplVersion1"; it is grown
103
// historically and really would benefit from a decomposition
104
**************************************************************************/
105
106
class Packer /*not_final*/ : public PackerBase {
107
protected:
108
    explicit Packer(InputFile *f);
109
110
public:
111
    virtual ~Packer() noexcept;
112
113
    // PackMaster entries
114
    virtual void assertPacker() const override;
115
    virtual void initPackHeader() final override;
116
    virtual void updatePackHeader() final override;
117
    virtual void doPack(OutputFile *fo) final override;
118
    virtual void doUnpack(OutputFile *fo) final override;
119
    virtual void doTest() final override;
120
    virtual void doList() final override;
121
    virtual void doFileInfo() final override;
122
123
    // unpacker capabilities
124
6.39k
    virtual bool canUnpackVersion(int version) const { return (version >= 8); }
125
16.9k
    virtual bool canUnpackFormat(int format) const { return (format == getFormat()); }
126
127
protected:
128
    // unpacker tests - these may throw exceptions
129
    virtual bool testUnpackVersion(int version) const may_throw;
130
    virtual bool testUnpackFormat(int format) const may_throw;
131
132
protected:
133
    // implementation
134
    virtual void pack(OutputFile *fo) = 0;
135
    virtual void unpack(OutputFile *fo) = 0;
136
    virtual void test();
137
    virtual void list();
138
    virtual void fileInfo();
139
140
protected:
141
    // main compression drivers
142
    bool compress(SPAN_P(byte) i_ptr, unsigned i_len, SPAN_P(byte) o_ptr,
143
                  const upx_compress_config_t *cconf = nullptr);
144
    void decompress(SPAN_P(const byte) in, SPAN_P(byte) out, bool verify_checksum = true,
145
                    Filter *ft = nullptr);
146
    virtual bool checkDefaultCompressionRatio(unsigned u_len, unsigned c_len) const;
147
    virtual bool checkCompressionRatio(unsigned u_len, unsigned c_len) const;
148
    virtual bool checkFinalCompressionRatio(const OutputFile *fo) const;
149
150
    // high-level compression drivers
151
    void compressWithFilters(Filter *ft, const unsigned overlap_range,
152
                             const upx_compress_config_t *cconf, int filter_strategy = 0,
153
                             bool inhibit_compression_check = false);
154
    void compressWithFilters(Filter *ft, const unsigned overlap_range,
155
                             const upx_compress_config_t *cconf, int filter_strategy,
156
                             unsigned filter_buf_off, unsigned compress_ibuf_off,
157
                             unsigned compress_obuf_off, byte *const hdr_ptr, unsigned hdr_len,
158
                             bool inhibit_compression_check = false);
159
    // real compression driver
160
    void compressWithFilters(byte *i_ptr, unsigned i_len, // written and restored by filters
161
                             byte *o_ptr, byte *f_ptr,
162
                             unsigned f_len, // subset of [*i_ptr, +i_len)
163
                             byte *const hdr_ptr, unsigned hdr_len,
164
                             Filter *parm_ft, // updated
165
                             unsigned overlap_range, const upx_compress_config_t *cconf,
166
                             int filter_strategy, bool inhibit_compression_check = false);
167
168
    // util for verifying overlapping decompression
169
    //   non-destructive test
170
    virtual bool testOverlappingDecompression(const byte *buf, const byte *tbuf,
171
                                              unsigned overlap_overhead) const;
172
    //   non-destructive find
173
    virtual unsigned findOverlapOverhead(const byte *buf, const byte *tbuf, unsigned range = 0,
174
                                         unsigned upper_limit = ~0u) const;
175
    //   destructive decompress + verify
176
    void verifyOverlappingDecompression(Filter *ft = nullptr);
177
    void verifyOverlappingDecompression(byte *o_ptr, unsigned o_size, Filter *ft = nullptr);
178
179
    // packheader handling
180
    virtual int patchPackHeader(void *b, int blen) final;
181
    virtual bool getPackHeader(const void *b, int blen, bool allow_incompressible = false) final;
182
    virtual bool readPackHeader(int len, bool allow_incompressible = false) final;
183
    virtual void checkAlreadyPacked(const void *b, int blen) final;
184
185
    // loader core
186
    virtual void buildLoader(const Filter *ft) = 0;
187
    virtual Linker *newLinker() const = 0;
188
    virtual void relocateLoader();
189
    // loader util for linker
190
    virtual byte *getLoader() const;
191
    virtual int getLoaderSize() const;
192
    virtual void initLoader(unsigned arch, const void *pdata, int plen, int small = -1,
193
                            int pextra = 0);
194
#define C const char *
195
    void addLoader(C);
196
    void addLoader(C, C);
197
    void addLoader(C, C, C);
198
    void addLoader(C, C, C, C);
199
    void addLoader(C, C, C, C, C);
200
    void addLoader(C, C, C, C, C, C);
201
    void addLoader(C, C, C, C, C, C, C);
202
    void addLoader(C, C, C, C, C, C, C, C);
203
    void addLoader(C, C, C, C, C, C, C, C, C);
204
    void addLoader(C, C, C, C, C, C, C, C, C, C);
205
#undef C
206
#if (ACC_CC_CLANG || ACC_CC_GNUC)
207
    void addLoaderVA(const char *s, ...) __attribute__((__sentinel__));
208
#else
209
    void addLoaderVA(const char *s, ...);
210
#endif
211
    virtual bool hasLoaderSection(const char *name) const;
212
    virtual int getLoaderSection(const char *name, int *slen = nullptr) const;
213
    virtual int getLoaderSectionStart(const char *name, int *slen = nullptr) const;
214
215
    // compression handling [see packer_c.cpp]
216
public:
217
    static bool isValidFormat(int format) noexcept;
218
    static bool isValidCompressionMethod(int method) noexcept;
219
220
protected:
221
    const int *getDefaultCompressionMethods_8(int method, int level, int small = -1) const;
222
    const int *getDefaultCompressionMethods_le32(int method, int level, int small = -1) const;
223
    int prepareMethods(int *methods, int ph_method, const int *all_methods) const;
224
    virtual const char *getDecompressorSections() const;
225
    virtual unsigned getDecompressorWrkmemSize() const;
226
    virtual void defineDecompressorSymbols();
227
228
    // filter handling [see packer_f.cpp]
229
    virtual bool isValidFilter(int filter_id) const;
230
0
    virtual void optimizeFilter(Filter *, const byte *, unsigned) const {}
231
    virtual void addFilter32(int filter_id);
232
    virtual void defineFilterSymbols(const Filter *ft);
233
234
    // stub and overlay util
235
    static void handleStub(InputFile *fi, OutputFile *fo, unsigned size);
236
    virtual void checkOverlay(unsigned overlay);
237
    virtual void copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer &buf, bool do_seek = true);
238
239
    // misc util
240
    virtual unsigned getRandomId() const;
241
242
    // patch util
243
    int patch_be16(void *b, int blen, unsigned old, unsigned new_);
244
    int patch_be16(void *b, int blen, const void *old, unsigned new_);
245
    int patch_be32(void *b, int blen, unsigned old, unsigned new_);
246
    int patch_be32(void *b, int blen, const void *old, unsigned new_);
247
    int patch_le16(void *b, int blen, unsigned old, unsigned new_);
248
    int patch_le16(void *b, int blen, const void *old, unsigned new_);
249
    int patch_le32(void *b, int blen, unsigned old, unsigned new_);
250
    int patch_le32(void *b, int blen, const void *old, unsigned new_);
251
    void checkPatch(void *b, int blen, int boff, int size);
252
253
    // relocation util [see packer_r.cpp]
254
    static unsigned optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(byte) out,
255
                                  SPAN_P(byte) image, unsigned image_size, int bits, bool bswap,
256
                                  int *big);
257
    static unsigned unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P(byte) image,
258
                                    unsigned image_size, int bits, bool bswap);
259
260
    // TE - Target Endianness abstraction
261
#if !(DEBUG)
262
    // permissive version using "void *"
263
654k
    inline unsigned get_te16(const void *p) const noexcept { return bele->get16(p); }
264
679k
    inline unsigned get_te32(const void *p) const noexcept { return bele->get32(p); }
265
0
    inline unsigned get_te64_32(const void *p) const may_throw {
266
0
        upx_uint64_t v = bele->get64(p);
267
0
        if very_unlikely ((v >> 32) != 0)
268
0
            throwCantPack("64-bit value too big %#llx", v);
269
0
        return (unsigned) v;
270
0
    }
271
229k
    inline upx_uint64_t get_te64(const void *p) const noexcept { return bele->get64(p); }
272
0
    inline void set_te16(void *p, unsigned v) noexcept { bele->set16(p, v); }
273
0
    inline void set_te32(void *p, unsigned v) noexcept { bele->set32(p, v); }
274
0
    inline void set_te64(void *p, upx_uint64_t v) noexcept { bele->set64(p, v); }
275
#else
276
    // try to detect TE16 vs TE32 vs TE64 size mismatches; note that byte is explicitly allowed
277
    template <class T>
278
    static inline constexpr bool is_te16_type =
279
        upx::is_same_any_v<T, byte, upx_uint16_t, BE16, LE16>;
280
    template <class T>
281
    static inline constexpr bool is_te32_type =
282
        upx::is_same_any_v<T, byte, upx_uint32_t, BE32, LE32>;
283
    template <class T>
284
    static inline constexpr bool is_te64_type =
285
        upx::is_same_any_v<T, byte, upx_uint64_t, BE64, LE64>;
286
287
    template <class T>
288
    using enable_if_te16 = std::enable_if_t<is_te16_type<T>, T>;
289
    template <class T>
290
    using enable_if_te32 = std::enable_if_t<is_te32_type<T>, T>;
291
    template <class T>
292
    using enable_if_te64 = std::enable_if_t<is_te64_type<T>, T>;
293
294
    template <class T, class = enable_if_te16<T> >
295
    inline unsigned get_te16(const T *p) const noexcept {
296
        return bele->get16(p);
297
    }
298
    template <class T, class = enable_if_te32<T> >
299
    inline unsigned get_te32(const T *p) const noexcept {
300
        return bele->get32(p);
301
    }
302
    template <class T, class = enable_if_te64<T> >
303
    inline unsigned get_te64_32(const T *p) const may_throw {
304
        upx_uint64_t v = bele->get64(p);
305
        if very_unlikely ((v >> 32) != 0)
306
            throwCantPack("64-bit value too big %#llx", v);
307
        return (unsigned) v;
308
    }
309
    template <class T, class = enable_if_te64<T> >
310
    inline upx_uint64_t get_te64(const T *p) const noexcept {
311
        return bele->get64(p);
312
    }
313
314
    template <class T, class = enable_if_te16<T> >
315
    inline void set_te16(T *p, unsigned v) noexcept {
316
        bele->set16(p, v);
317
    }
318
    template <class T, class = enable_if_te32<T> >
319
    inline void set_te32(T *p, unsigned v) noexcept {
320
        bele->set32(p, v);
321
    }
322
    template <class T, class = enable_if_te64<T> >
323
    inline void set_te64(T *p, upx_uint64_t v) noexcept {
324
        bele->set64(p, v);
325
    }
326
#endif
327
328
protected:
329
    const N_BELE_RTP::AbstractPolicy *bele = nullptr; // TE - Target Endianness
330
331
    // PackHeader
332
    int ph_format = -1;
333
    int ph_version = -1;
334
335
    // compression buffers
336
    MemBuffer ibuf;        // input
337
    MemBuffer obuf;        // output
338
    unsigned ibufgood = 0; // high-water mark in ibuf (pefile.cpp)
339
340
    // UI handler
341
    OwningPointer(UiPacker) uip = nullptr; // owner
342
343
    // linker
344
    OwningPointer(Linker) linker = nullptr; // owner
345
346
private:
347
    // private to checkPatch()
348
    void *last_patch = nullptr;
349
    int last_patch_len = 0;
350
    int last_patch_off = 0;
351
352
private:
353
    // disable copy and move
354
    UPX_CXX_DISABLE_COPY_MOVE(Packer)
355
};
356
357
/* vim:set ts=4 sw=4 et: */