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