1 /* packer_c.cpp -- Packer compression handling
2 
3    This file is part of the UPX executable compressor.
4 
5    Copyright (C) 1996-2020 Markus Franz Xaver Johannes Oberhumer
6    Copyright (C) 1996-2020 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 
29 #include "conf.h"
30 #include "packer.h"
31 #include "linker.h"
32 //#include "filter.h"
33 
34 
35 /*************************************************************************
36 // compression method util
37 **************************************************************************/
38 
isValidCompressionMethod(int method)39 bool Packer::isValidCompressionMethod(int method)
40 {
41     if (M_IS_LZMA(method)) {
42 #if !(WITH_LZMA)
43         assert(0 && "Internal error - LZMA not compiled in");
44 #else
45         return true;
46 #endif
47     }
48     return (method >= M_NRV2B_LE32 && method <= M_LZMA);
49 }
50 
51 
getDefaultCompressionMethods_8(int method,int level,int small) const52 const int *Packer::getDefaultCompressionMethods_8(int method, int level, int small) const
53 {
54 #define M_LZMA_003      (M_LZMA | 0x00300)
55 #define M_LZMA_407      (M_LZMA | 0x40700)
56     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 };
57     //static const int m_cl1b[]  = { M_CL1B_8, M_END };
58     static const int m_lzma[]  = { M_LZMA, M_END };
59     static const int m_nrv2b[] = { M_NRV2B_8, M_END };
60     static const int m_nrv2d[] = { M_NRV2D_8, M_END };
61     static const int m_nrv2e[] = { M_NRV2E_8, M_END };
62 
63     if (method == M_ALL)    return m_all;
64     //if (M_IS_CL1B(method))  return m_cl1b;
65     if (M_IS_LZMA(method))  return m_lzma;
66     if (M_IS_NRV2B(method)) return m_nrv2b;
67     if (M_IS_NRV2D(method)) return m_nrv2d;
68     if (M_IS_NRV2E(method)) return m_nrv2e;
69     if (small < 0)
70         small = file_size <= 512*1024;
71     if (level == 1 || small)
72         return m_nrv2b;
73     return m_nrv2e;
74 }
75 
76 
getDefaultCompressionMethods_le32(int method,int level,int small) const77 const int *Packer::getDefaultCompressionMethods_le32(int method, int level, int small) const
78 {
79     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 };
80     //static const int m_cl1b[]  = { M_CL1B_LE32, M_END };
81     static const int m_lzma[]  = { M_LZMA, M_END };
82     static const int m_nrv2b[] = { M_NRV2B_LE32, M_END };
83     static const int m_nrv2d[] = { M_NRV2D_LE32, M_END };
84     static const int m_nrv2e[] = { M_NRV2E_LE32, M_END };
85 
86     if (method == M_ALL)    return m_all;
87     //if (M_IS_CL1B(method))  return m_cl1b;
88     if (M_IS_LZMA(method))  return m_lzma;
89     if (M_IS_NRV2B(method)) return m_nrv2b;
90     if (M_IS_NRV2D(method)) return m_nrv2d;
91     if (M_IS_NRV2E(method)) return m_nrv2e;
92     if (small < 0)
93         small = file_size <= 512*1024;
94     if (level == 1 || small)
95         return m_nrv2b;
96     return m_nrv2e;
97 }
98 
99 
100 /*************************************************************************
101 // loader util
102 **************************************************************************/
103 
getDecompressorSections() const104 const char *Packer::getDecompressorSections() const
105 {
106     static const char nrv2b_le32_small[] =
107         "N2BSMA10,N2BDEC10,N2BSMA20,N2BDEC20,N2BSMA30,"
108         "N2BDEC30,N2BSMA40,N2BSMA50,N2BDEC50,N2BSMA60,"
109         "N2BDEC60";
110     static const char nrv2b_le32_fast[] =
111         "N2BFAS10,+80CXXXX,N2BFAS11,N2BDEC10,N2BFAS20,"
112         "N2BDEC20,N2BFAS30,N2BDEC30,N2BFAS40,N2BFAS50,"
113         "N2BDEC50,N2BFAS60,+40CXXXX,N2BFAS61,N2BDEC60";
114     static const char nrv2d_le32_small[] =
115         "N2DSMA10,N2DDEC10,N2DSMA20,N2DDEC20,N2DSMA30,"
116         "N2DDEC30,N2DSMA40,N2DSMA50,N2DDEC50,N2DSMA60,"
117         "N2DDEC60";
118     static const char nrv2d_le32_fast[] =
119         "N2DFAS10,+80CXXXX,N2DFAS11,N2DDEC10,N2DFAS20,"
120         "N2DDEC20,N2DFAS30,N2DDEC30,N2DFAS40,N2DFAS50,"
121         "N2DDEC50,N2DFAS60,+40CXXXX,N2DFAS61,N2DDEC60";
122     static const char nrv2e_le32_small[] =
123         "N2ESMA10,N2EDEC10,N2ESMA20,N2EDEC20,N2ESMA30,"
124         "N2EDEC30,N2ESMA40,N2ESMA50,N2EDEC50,N2ESMA60,"
125         "N2EDEC60";
126     static const char nrv2e_le32_fast[] =
127         "N2EFAS10,+80CXXXX,N2EFAS11,N2EDEC10,N2EFAS20,"
128         "N2EDEC20,N2EFAS30,N2EDEC30,N2EFAS40,N2EFAS50,"
129         "N2EDEC50,N2EFAS60,+40CXXXX,N2EFAS61,N2EDEC60";
130 #if 0
131     static const char cl1b_le32_small[] =
132         "CL1ENTER,CL1SMA10,CL1RLOAD,"
133         "CL1WID01,CL1SMA1B,"
134         "CL1WID02,CL1SMA1B,"
135         "CL1WID03,CL1SMA1B,"
136         "CL1WID04,CL1SMA1B,"
137         "CL1WID05,CL1SMA1B,"
138         "CL1WID06,CL1SMA1B,"
139         "CL1WID07,CL1SMA1B,"
140         "CL1WID08,CL1SMA1B,"
141         "CL1WID09,CL1SMA1B,"
142         "CL1WID10,"
143         "CL1START,"
144         "CL1TOP00,CL1SMA1B,"
145         "CL1TOP01,CL1SMA1B,"
146         "CL1TOP02,CL1SMA1B,"
147         "CL1TOP03,CL1SMA1B,"
148         "CL1TOP04,CL1SMA1B,"
149         "CL1TOP05,CL1SMA1B,"
150         "CL1TOP06,CL1SMA1B,"
151         "CL1TOP07,CL1SMA1B,"
152         "CL1OFF01,CL1SMA1B,"
153         "CL1OFF02,CL1SMA1B,"
154         "CL1OFF03,CL1SMA1B,"
155         "CL1OFF04,"
156         "CL1LEN00,CL1SMA1B,"
157         "CL1LEN01,CL1SMA1B,"
158         "CL1LEN02,"
159         "CL1COPY0";
160     static const char cl1b_le32_fast[] =
161         "CL1ENTER,"          "CL1RLOAD,"
162         "CL1WID01,CL1FAS1B,"
163         "CL1WID02,CL1FAS1B,"
164         "CL1WID03,CL1FAS1B,"
165         "CL1WID04,CL1FAS1B,"
166         "CL1WID05,CL1FAS1B,"
167         "CL1WID06,CL1FAS1B,"
168         "CL1WID07,CL1FAS1B,"
169         "CL1WID08,CL1FAS1B,"
170         "CL1WID09,CL1FAS1B,"
171         "CL1WID10,"
172         "CL1START,"
173         "CL1TOP00,CL1FAS1B,"
174         "CL1TOP01,CL1FAS1B,"
175         "CL1TOP02,CL1FAS1B,"
176         "CL1TOP03,CL1FAS1B,"
177         "CL1TOP04,CL1FAS1B,"
178         "CL1TOP05,CL1FAS1B,"
179         "CL1TOP06,CL1FAS1B,"
180         "CL1TOP07,CL1FAS1B,"
181         "CL1OFF01,CL1FAS1B,"
182         "CL1OFF02,CL1FAS1B,"
183         "CL1OFF03,CL1FAS1B,"
184         "CL1OFF04,"
185         "CL1LEN00,CL1FAS1B,"
186         "CL1LEN01,CL1FAS1B,"
187         "CL1LEN02,"
188         "CL1COPY0";
189 #endif
190     static const char lzma_small[] =
191         "LZMA_DEC00,LZMA_DEC10,LZMA_DEC30";
192     static const char lzma_fast[] =
193         "LZMA_DEC00,LZMA_DEC20,LZMA_DEC30";
194     static const char lzma_elf_small[] =
195         "LZMA_ELF00,LZMA_DEC10,LZMA_DEC30";
196     static const char lzma_elf_fast[] =
197         "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30";
198 
199     if (ph.method == M_NRV2B_LE32)
200         return opt->small ? nrv2b_le32_small : nrv2b_le32_fast;
201     if (ph.method == M_NRV2D_LE32)
202         return opt->small ? nrv2d_le32_small : nrv2d_le32_fast;
203     if (ph.method == M_NRV2E_LE32)
204         return opt->small ? nrv2e_le32_small : nrv2e_le32_fast;
205 //    if (ph.method == M_CL1B_LE32)
206 //        return opt->small ? cl1b_le32_small  : cl1b_le32_fast;
207     if (M_IS_LZMA(ph.method)) {
208         if (UPX_F_LINUX_ELF_i386   ==ph.format
209         ||  UPX_F_LINUX_ELFI_i386  ==ph.format
210         ||  UPX_F_LINUX_ELF64_AMD  ==ph.format
211         ||  UPX_F_LINUX_ELF32_ARMEL==ph.format
212         ||  UPX_F_LINUX_ELFPPC32   ==ph.format
213         ||  UPX_F_LINUX_ELFPPC64LE ==ph.format
214         ||  UPX_F_LINUX_ELF32_ARMEB==ph.format
215         ||  UPX_F_BSD_ELF_i386     ==ph.format
216         ||  UPX_F_VMLINUZ_ARMEL    ==ph.format
217         ||  UPX_F_VMLINUX_ARMEL    ==ph.format
218         ||  UPX_F_VMLINUX_ARMEB    ==ph.format
219         ||  UPX_F_VMLINUX_PPC32    ==ph.format
220         ||  UPX_F_VMLINUX_PPC64LE  ==ph.format
221         ||  UPX_F_MACH_PPC32       ==ph.format
222         ||  UPX_F_MACH_PPC64LE     ==ph.format
223         ||  UPX_F_MACH_i386        ==ph.format
224         ||  UPX_F_DYLIB_i386       ==ph.format
225     ) {
226             return opt->small ? lzma_elf_small  : lzma_elf_fast;
227         }
228         return opt->small ? lzma_small  : lzma_fast;
229     }
230     throwInternalError("bad decompressor");
231     return NULL;
232 }
233 
234 
getDecompressorWrkmemSize() const235 unsigned Packer::getDecompressorWrkmemSize() const
236 {
237     unsigned size = 0;
238     if (M_IS_LZMA(ph.method))
239     {
240         const lzma_compress_result_t *res = &ph.compress_result.result_lzma;
241         // FIXME - this is for i386 only
242         size = 8 + 4 + ALIGN_UP(2 * res->num_probs, 4u);
243         size = ALIGN_UP(size, 16u);
244     }
245     assert((int)size >= 0);
246     return size;
247 }
248 
defineDecompressorSymbols()249 void Packer::defineDecompressorSymbols()
250 {
251     if (UPX_F_LINUX_ELF_i386   ==ph.format
252     ||  UPX_F_LINUX_ELFI_i386  ==ph.format
253     ||  UPX_F_LINUX_ELF64_AMD  ==ph.format
254     ||  UPX_F_LINUX_ELF32_ARMEL==ph.format
255     ||  UPX_F_LINUX_ELFPPC32   ==ph.format
256     ||  UPX_F_LINUX_ELFPPC64LE ==ph.format
257     ||  UPX_F_LINUX_ELF32_ARMEB==ph.format
258     ||  UPX_F_BSD_ELF_i386     ==ph.format
259     ||  UPX_F_VMLINUZ_ARMEL    ==ph.format
260     ||  UPX_F_VMLINUX_ARMEL    ==ph.format
261     ||  UPX_F_VMLINUX_ARMEB    ==ph.format
262     ||  UPX_F_VMLINUX_PPC32    ==ph.format
263     ||  UPX_F_VMLINUX_PPC64LE  ==ph.format
264     ||  UPX_F_MACH_PPC32       ==ph.format
265     ||  UPX_F_MACH_PPC64LE     ==ph.format
266     ||  UPX_F_MACH_i386        ==ph.format
267     ||  UPX_F_DYLIB_i386       ==ph.format
268     ) {
269         // ELF calls the decompressor many times; the parameters change!
270         return;
271     }
272     if (M_IS_LZMA(ph.method))
273     {
274         const lzma_compress_result_t *res = &ph.compress_result.result_lzma;
275         upx_uint32_t properties = // lc, lp, pb, dummy
276             (res->lit_context_bits << 0) |
277             (res->lit_pos_bits << 8) |
278             (res->pos_bits << 16);
279         if (linker->bele->isBE()) // big endian - bswap32
280             acc_swab32s(&properties);
281 
282         linker->defineSymbol("lzma_properties", properties);
283         // len - 2 because of properties
284         linker->defineSymbol("lzma_c_len", ph.c_len - 2);
285         linker->defineSymbol("lzma_u_len", ph.u_len);
286         unsigned stack = getDecompressorWrkmemSize();
287         linker->defineSymbol("lzma_stack_adjust", 0u - stack);
288 
289         if (ph.format == UPX_F_DOS_EXE)
290         {
291             linker->defineSymbol("lzma_properties_hi", properties >> 16);   // pb
292             linker->defineSymbol("lzma_c_len_hi", (ph.c_len - 2) >> 16);
293             linker->defineSymbol("lzma_u_len_hi", ph.u_len >> 16);
294             linker->defineSymbol("lzma_u_len_segment", (ph.u_len & 0xf0000) >> 4);
295         }
296     }
297 }
298 
299 /* vim:set ts=4 sw=4 et: */
300