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