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: */ |