1 /* p_lx_interp.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    Copyright (C) 2000-2020 John F. Reiser
8    All Rights Reserved.
9 
10    UPX and the UCL library are free software; you can redistribute them
11    and/or modify them under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2 of
13    the License, or (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; see the file COPYING.
22    If not, write to the Free Software Foundation, Inc.,
23    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25    Markus F.X.J. Oberhumer              Laszlo Molnar
26    <markus@oberhumer.com>               <ezerotven+github@gmail.com>
27 
28    John F. Reiser
29    <jreiser@users.sourceforge.net>
30  */
31 
32 
33 #include "conf.h"
34 
35 #include "file.h"
36 #include "filter.h"
37 #include "linker.h"
38 #include "packer.h"
39 #include "p_elf.h"
40 #include "p_unix.h"
41 #include "p_lx_exc.h"
42 #include "p_lx_elf.h"
43 #include "p_lx_interp.h"
44 
45 #define PT_LOAD     Elf32_Phdr::PT_LOAD
46 #define PT_INTERP   Elf32_Phdr::PT_INTERP
47 
48 
49 /*************************************************************************
50 //
51 **************************************************************************/
52 
53 static const
54 #include "stub/i386-linux.elf.interp-entry.h"
55 static const
56 #include "stub/i386-linux.elf.interp-fold.h"
57 
PackLinuxElf32x86interp(InputFile * f)58 PackLinuxElf32x86interp::PackLinuxElf32x86interp(InputFile *f) :
59     super(f)
60 {
61 }
62 
~PackLinuxElf32x86interp()63 PackLinuxElf32x86interp::~PackLinuxElf32x86interp()
64 {
65 }
66 
canPack()67 bool PackLinuxElf32x86interp::canPack()
68 {
69     if (opt->o_unix.make_ptinterp) {
70         return true;
71     }
72     if (!opt->o_unix.use_ptinterp) {
73         return false;
74     }
75     return super::canPack();
76 }
77 
pack1(OutputFile * fo,Filter &)78 void PackLinuxElf32x86interp::pack1(OutputFile *fo, Filter &)
79 {
80     fi->seek(0, SEEK_SET);
81     fi->readx(&ehdri, sizeof(ehdri));
82     assert(ehdri.e_phoff == sizeof(Elf32_Ehdr));  // checked by canPack()
83     sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize;
84 
85     phdri = New(Elf32_Phdr, ehdri.e_phnum);
86     fi->seek(ehdri.e_phoff, SEEK_SET);
87     fi->readx(phdri, sz_phdrs);
88 
89 #define E Elf32_Ehdr
90     cprElfHdr3 h3;
91     memset(&h3, 0, sizeof(h3));
92     memcpy(h3.ehdr.e_ident, "\177ELF", 4);
93     h3.ehdr.e_ident[E::EI_CLASS] = E::ELFCLASS32;
94     h3.ehdr.e_ident[E::EI_DATA] = E::ELFDATA2LSB;
95     h3.ehdr.e_ident[E::EI_VERSION] = E::EV_CURRENT;
96     h3.ehdr.e_ident[E::EI_OSABI] = E::ELFOSABI_LINUX;
97     h3.ehdr.e_ident[E::EI_ABIVERSION] = E::EV_CURRENT;
98     h3.ehdr.e_type = E::ET_EXEC;
99     h3.ehdr.e_machine = E::EM_386;
100     h3.ehdr.e_version = 1;
101     h3.ehdr.e_phoff = sizeof(Elf32_Ehdr);
102     h3.ehdr.e_ehsize = sizeof(Elf32_Ehdr);
103     h3.ehdr.e_phentsize = sizeof(Elf32_Phdr);
104     h3.ehdr.e_phnum = 3;
105     h3.phdr[0].p_type = PT_LOAD;
106     h3.phdr[0].p_flags = Elf32_Phdr::PF_X | Elf32_Phdr::PF_R;
107     h3.phdr[0].p_align = 0x1000;
108     h3.phdr[1].p_type = PT_LOAD;
109     h3.phdr[1].p_flags = Elf32_Phdr::PF_W | Elf32_Phdr::PF_R;
110     h3.phdr[1].p_align = 1;
111     h3.phdr[2].p_type = PT_INTERP;
112     h3.phdr[2].p_offset = (char *)&h3.phdr[2].p_vaddr - (char *)&h3;
113     memcpy(&h3.phdr[2].p_vaddr, "/upxrun", h3.phdr[2].p_filesz = 8);
114     h3.phdr[2].p_align = 1;
115 
116     if (opt->o_unix.make_ptinterp) { // unusual "once per release"
117         *(cprElfHdr3 *)(void *)&elfout = h3;
118         elfout.ehdr.e_phnum = 1;
119         fo->write(&elfout, elfout.ehdr.e_ehsize + elfout.ehdr.e_phentsize);
120     }
121     else { // usual case
122         generateElfHdr(fo, &h3, getbrk(phdri, ehdri.e_phnum));
123     }
124 #undef E
125 }
126 
pack2(OutputFile * fo,Filter & ft)127 int PackLinuxElf32x86interp::pack2(OutputFile *fo, Filter &ft)
128 {
129     if (opt->o_unix.make_ptinterp) {
130         return 1;  // ignore current input file!
131     }
132     return super::pack2(fo, ft);
133 }
134 
135 #undef PAGE_MASK
136 #define PAGE_MASK (~0u<<12)
137 
pack3(OutputFile * fo,Filter &)138 off_t PackLinuxElf32x86interp::pack3(OutputFile *fo, Filter &/*ft*/)
139 {
140     unsigned base = getbase(phdri, ehdri.e_phnum);
141     unsigned sz = PAGE_MASK & (~PAGE_MASK + elfout.phdr[0].p_filesz);
142     if (base < (0x11000 + sz)) {
143         base =  0x11000 + sz;
144     }
145     if (opt->o_unix.make_ptinterp) {
146         base = 0x10000;
147     }
148     elfout.phdr[0].p_paddr = elfout.phdr[0].p_vaddr = base - sz;
149     if (opt->o_unix.make_ptinterp) {
150         initLoader(stub_i386_linux_elf_interp_entry, sizeof(stub_i386_linux_elf_interp_entry));
151         linker->addSection("FOLDEXEC", stub_i386_linux_elf_interp_fold, sizeof(stub_i386_linux_elf_interp_fold), 0);
152 
153         addLoader("LXPTI000", NULL);
154 
155         addLoader("LXPTI040", NULL);
156         ph.method = M_NRV2B_LE32; addLoader(getDecompressorSections(), NULL);
157         addLoader("LXPTI090", NULL);
158 
159         addLoader("LXPTI041", NULL);
160         ph.method = M_NRV2D_LE32; addLoader(getDecompressorSections(), NULL);
161         addLoader("LXPTI090", NULL);
162 
163         addLoader("LXPTI042", NULL);
164         ph.method = M_NRV2E_LE32; addLoader(getDecompressorSections(), NULL);
165         addLoader("LXPTI090", NULL);
166 
167         //addLoader("LXPTI043", NULL);
168         //ph.method = M_CL1B_LE32;  addLoader(getDecompressorSections(), NULL);
169         //addLoader("LXPTI090", NULL);
170 
171         addLoader("LXPTI091", NULL);
172 
173         addLoader("LXPTI140", NULL);
174 
175         addLoader("LXUNF002,LXUNF008,LXUNF010", NULL);
176         addFilter32(0x46);
177         addLoader("LXUNF042,LXUNF035", NULL);
178 
179         addLoader("LXUNF002,LXUNF008,LXUNF010", NULL);
180         addFilter32(0x49);
181         addLoader("LXUNF042,LXUNF035", NULL);
182 
183         addLoader("LXPTI200", NULL);
184         addLoader("FOLDEXEC", NULL);
185         upx_byte const *p = getLoader();
186         lsize = getLoaderSize();
187         updateLoader(fo);
188         fo->write(p, lsize);
189         elfout.phdr[0].p_filesz = fo->getBytesWritten();
190     }
191     else {
192         updateLoader(fo);
193     }
194     return fo->getBytesWritten();
195 }
196 
197 
unpack(OutputFile * fo)198 void PackLinuxElf32x86interp::unpack(OutputFile *fo)
199 {
200 #define MAX_INTERP_HDR 512
201     union {
202         unsigned char buf[MAX_INTERP_HDR];
203         //struct { Elf32_Ehdr ehdr; Elf32_Phdr phdr; } e;
204     } u;
205     Elf32_Ehdr *const ehdr = (Elf32_Ehdr *) u.buf;
206     Elf32_Phdr const *phdr = (Elf32_Phdr *) (u.buf + sizeof(*ehdr));
207 
208     unsigned szb_info = sizeof(b_info);
209     {
210         fi->seek(0, SEEK_SET);
211         fi->readx(u.buf, MAX_INTERP_HDR);
212         unsigned const e_entry = get_te32(&ehdr->e_entry);
213         if (e_entry < 0x401180) { /* old style, 8-byte b_info */
214             szb_info = 2*sizeof(unsigned);
215         }
216     }
217 
218     fi->seek(overlay_offset, SEEK_SET);
219     p_info hbuf;
220     fi->readx(&hbuf, sizeof(hbuf));
221     unsigned orig_file_size = get_te32(&hbuf.p_filesize);
222     blocksize = get_te32(&hbuf.p_blocksize);
223     if (file_size > (off_t)orig_file_size || blocksize > orig_file_size)
224         throwCantUnpack("file header corrupted");
225 
226     ibuf.alloc(blocksize + OVERHEAD);
227     b_info bhdr; memset(&bhdr, 0, sizeof(bhdr));
228     fi->readx(&bhdr, szb_info);
229     ph.u_len = get_te32(&bhdr.sz_unc);
230     ph.c_len = get_te32(&bhdr.sz_cpr);
231     ph.filter_cto = bhdr.b_cto8;
232 
233     // Uncompress Ehdr and Phdrs.
234     fi->readx(ibuf, ph.c_len);
235     decompress(ibuf, (upx_byte *)ehdr, false);
236 
237     unsigned total_in = 0;
238     unsigned total_out = 0;
239     unsigned c_adler = upx_adler32(NULL, 0);
240     unsigned u_adler = upx_adler32(NULL, 0);
241     off_t ptload0hi=0, ptload1lo=0, ptload1sz=0;
242 
243     // decompress PT_LOAD
244     bool first_PF_X = true;
245     fi->seek(- (off_t) (szb_info + ph.c_len), SEEK_CUR);
246     for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) {
247         if (PT_LOAD==phdr->p_type) {
248             if (0==ptload0hi) {
249                 ptload0hi = phdr->p_filesz + phdr->p_offset;
250             }
251             else if (0==ptload1lo) {
252                 ptload1lo = phdr->p_offset;
253                 ptload1sz = phdr->p_filesz;
254             }
255             if (fo)
256                 fo->seek(phdr->p_offset, SEEK_SET);
257             if (Elf32_Phdr::PF_X & phdr->p_flags) {
258                 unpackExtent(phdr->p_filesz, fo, total_in, total_out,
259                     c_adler, u_adler, first_PF_X, szb_info);
260                 first_PF_X = false;
261             }
262             else {
263                 unpackExtent(phdr->p_filesz, fo, total_in, total_out,
264                     c_adler, u_adler, false, szb_info);
265             }
266         }
267     }
268 
269     if (0!=ptload1sz && ptload0hi < ptload1lo) {  // alignment hole?
270         if (fo)
271             fo->seek(ptload0hi, SEEK_SET);
272         unpackExtent(ptload1lo - ptload0hi, fo, total_in, total_out,
273             c_adler, u_adler, false, szb_info);
274     }
275     if (total_out != orig_file_size) {  // non-PT_LOAD stuff
276         if (fo)
277             fo->seek(0, SEEK_END);
278         unpackExtent(orig_file_size - total_out, fo, total_in, total_out,
279             c_adler, u_adler, false, szb_info);
280     }
281 
282     // check for end-of-file
283     fi->readx(&bhdr, szb_info);
284     unsigned const sz_unc = ph.u_len = get_te32(&bhdr.sz_unc);
285 
286     if (sz_unc == 0) { // uncompressed size 0 -> EOF
287         // note: magic is always stored le32
288         unsigned const sz_cpr = get_le32(&bhdr.sz_cpr);
289         if (sz_cpr != UPX_MAGIC_LE32)  // sz_cpr must be h->magic
290             throwCompressedDataViolation();
291     }
292     else { // extra bytes after end?
293         throwCompressedDataViolation();
294     }
295 
296     // update header with totals
297     ph.c_len = total_in;
298     ph.u_len = total_out;
299 
300     // all bytes must be written
301     if (total_out != orig_file_size)
302         throwEOFException();
303 
304     // finally test the checksums
305     if (ph.c_adler != c_adler || ph.u_adler != u_adler)
306         throwChecksumError();
307 #undef MAX_INTERP_HDR
308 }
309 
310 /* vim:set ts=4 sw=4 et: */
311