1 /* packmast.cpp --
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 #include "conf.h"
29 #include "file.h"
30 #include "packmast.h"
31 #include "packer.h"
32 #include "lefile.h"
33 #include "pefile.h"
34 #include "p_elf.h"
35
36 #include "p_com.h"
37 #include "p_djgpp2.h"
38 #include "p_exe.h"
39 #include "p_unix.h"
40 #include "p_lx_exc.h"
41 #include "p_lx_elf.h"
42 #include "p_lx_sh.h"
43 #include "p_lx_interp.h"
44 #include "p_sys.h"
45 #include "p_tos.h"
46 #include "p_wcle.h"
47 #include "p_tmt.h"
48 #include "p_w32pe.h"
49 #include "p_w64pep.h"
50 #include "p_vmlinz.h"
51 #include "p_vmlinx.h"
52 #include "p_ps1.h"
53 #include "p_mach.h"
54 #include "p_armpe.h"
55
56 /*************************************************************************
57 //
58 **************************************************************************/
59
PackMaster(InputFile * f,options_t * o)60 PackMaster::PackMaster(InputFile *f, options_t *o) : fi(f), p(NULL) {
61 // replace global options with local options
62 saved_opt = o;
63 if (o) {
64 memcpy(&this->local_options, o, sizeof(*o)); // struct copy
65 opt = &this->local_options;
66 }
67 }
68
~PackMaster()69 PackMaster::~PackMaster() {
70 fi = NULL;
71 delete p;
72 p = NULL;
73 // restore global options
74 if (saved_opt)
75 opt = saved_opt;
76 saved_opt = NULL;
77 }
78
79 /*************************************************************************
80 //
81 **************************************************************************/
82
try_pack(Packer * p,void * user)83 static Packer *try_pack(Packer *p, void *user) {
84 if (p == NULL)
85 return NULL;
86 InputFile *f = (InputFile *) user;
87 p->assertPacker();
88 try {
89 p->initPackHeader();
90 f->seek(0, SEEK_SET);
91 if (p->canPack()) {
92 if (opt->cmd == CMD_COMPRESS)
93 p->updatePackHeader();
94 f->seek(0, SEEK_SET);
95 return p;
96 }
97 } catch (const IOException &) {
98 } catch (...) {
99 delete p;
100 throw;
101 }
102 delete p;
103 return NULL;
104 }
105
try_unpack(Packer * p,void * user)106 static Packer *try_unpack(Packer *p, void *user) {
107 if (p == NULL)
108 return NULL;
109 InputFile *f = (InputFile *) user;
110 p->assertPacker();
111 try {
112 p->initPackHeader();
113 f->seek(0, SEEK_SET);
114 int r = p->canUnpack();
115 if (r > 0) {
116 f->seek(0, SEEK_SET);
117 return p;
118 }
119 if (r < 0) {
120 // FIXME - could stop testing all other unpackers at this time
121 // see canUnpack() in packer.h
122 }
123 } catch (const IOException &) {
124 } catch (...) {
125 delete p;
126 throw;
127 }
128 delete p;
129 return NULL;
130 }
131
132 /*************************************************************************
133 //
134 **************************************************************************/
135
visitAllPackers(visit_func_t func,InputFile * f,const options_t * o,void * user)136 Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const options_t *o,
137 void *user) {
138 Packer *p = NULL;
139
140 #define D(Klass) \
141 ACC_BLOCK_BEGIN \
142 Klass *const kp = new Klass(f); \
143 if (o->debug.debug_level) \
144 fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", kp->getVersion(), \
145 kp->getFormat(), #Klass); \
146 if ((p = func(kp, user)) != NULL) \
147 return p; \
148 ACC_BLOCK_END
149
150 // note: order of tries is important !
151
152 //
153 // .exe
154 //
155 if (!o->dos_exe.force_stub) {
156 D(PackDjgpp2);
157 D(PackTmt);
158 D(PackWcle);
159 D(PackW64Pep);
160 D(PackW32Pe);
161 }
162 D(PackArmPe);
163 D(PackExe);
164
165 //
166 // atari
167 //
168 D(PackTos);
169
170 //
171 // linux kernel
172 //
173 D(PackVmlinuxARMEL);
174 D(PackVmlinuxARMEB);
175 D(PackVmlinuxPPC32);
176 D(PackVmlinuxPPC64LE);
177 D(PackVmlinuxAMD64);
178 D(PackVmlinuxI386);
179 D(PackVmlinuzI386);
180 D(PackBvmlinuzI386);
181 D(PackVmlinuzARMEL);
182
183 //
184 // linux
185 //
186 if (!o->o_unix.force_execve) {
187 if (o->o_unix.use_ptinterp) {
188 D(PackLinuxElf32x86interp);
189 }
190 D(PackFreeBSDElf32x86);
191 D(PackNetBSDElf32x86);
192 D(PackOpenBSDElf32x86);
193 D(PackLinuxElf32x86);
194 D(PackLinuxElf64amd);
195 D(PackLinuxElf32armLe);
196 D(PackLinuxElf32armBe);
197 D(PackLinuxElf64arm);
198 D(PackLinuxElf32ppc);
199 D(PackLinuxElf64ppc);
200 D(PackLinuxElf64ppcle);
201 D(PackLinuxElf32mipsel);
202 D(PackLinuxElf32mipseb);
203 D(PackLinuxI386sh);
204 }
205 D(PackBSDI386);
206 D(PackMachFat); // cafebabe conflict
207 D(PackLinuxI386); // cafebabe conflict
208
209 //
210 // psone
211 //
212 D(PackPs1);
213
214 //
215 // .sys and .com
216 //
217 D(PackSys);
218 D(PackCom);
219
220 // Mach (MacOS X PowerPC)
221 D(PackDylibAMD64);
222 D(PackMachPPC32);
223 D(PackMachPPC64LE);
224 D(PackMachI386);
225 D(PackMachAMD64);
226 D(PackMachARMEL);
227 D(PackMachARM64EL);
228
229 // 2010-03-12 omit these because PackMachBase<T>::pack4dylib (p_mach.cpp)
230 // does not understand what the Darwin (Apple Mac OS X) dynamic loader
231 // assumes about .dylib file structure.
232 // D(PackDylibI386);
233 // D(PackDylibPPC32);
234
235 return NULL;
236 #undef D
237 }
238
getPacker(InputFile * f)239 Packer *PackMaster::getPacker(InputFile *f) {
240 Packer *pp = visitAllPackers(try_pack, f, opt, f);
241 if (!pp)
242 throwUnknownExecutableFormat();
243 pp->assertPacker();
244 return pp;
245 }
246
getUnpacker(InputFile * f)247 Packer *PackMaster::getUnpacker(InputFile *f) {
248 Packer *pp = visitAllPackers(try_unpack, f, opt, f);
249 if (!pp)
250 throwNotPacked();
251 pp->assertPacker();
252 return pp;
253 }
254
255 /*************************************************************************
256 // delegation
257 **************************************************************************/
258
pack(OutputFile * fo)259 void PackMaster::pack(OutputFile *fo) {
260 p = getPacker(fi);
261 fi = NULL;
262 p->doPack(fo);
263 }
264
unpack(OutputFile * fo)265 void PackMaster::unpack(OutputFile *fo) {
266 p = getUnpacker(fi);
267 p->assertPacker();
268 fi = NULL;
269 p->doUnpack(fo);
270 }
271
test()272 void PackMaster::test() {
273 p = getUnpacker(fi);
274 fi = NULL;
275 p->doTest();
276 }
277
list()278 void PackMaster::list() {
279 p = getUnpacker(fi);
280 fi = NULL;
281 p->doList();
282 }
283
fileInfo()284 void PackMaster::fileInfo() {
285 p = visitAllPackers(try_unpack, fi, opt, fi);
286 if (!p)
287 p = visitAllPackers(try_pack, fi, opt, fi);
288 if (!p)
289 throwUnknownExecutableFormat(NULL, 1); // make a warning here
290 p->assertPacker();
291 fi = NULL;
292 p->doFileInfo();
293 }
294
295 /* vim:set ts=4 sw=4 et: */
296