/src/upx/src/p_lx_exc.cpp
Line | Count | Source |
1 | | /* p_lx_exc.cpp -- |
2 | | |
3 | | This file is part of the UPX executable compressor. |
4 | | |
5 | | Copyright (C) 1996-2025 Markus Franz Xaver Johannes Oberhumer |
6 | | Copyright (C) 1996-2025 Laszlo Molnar |
7 | | Copyright (C) 2001-2025 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 | | |
43 | 0 | #define PT_LOAD Elf32_Phdr::PT_LOAD |
44 | | #define PT_DYNAMIC Elf32_Phdr::PT_DYNAMIC |
45 | | #if 0 // UNUSED |
46 | | #define DT_NULL Elf32_Dyn::DT_NULL |
47 | | #define DT_NEEDED Elf32_Dyn::DT_NEEDED |
48 | | #define DT_STRTAB Elf32_Dyn::DT_STRTAB |
49 | | #define DT_STRSZ Elf32_Dyn::DT_STRSZ |
50 | | #endif |
51 | | |
52 | | |
53 | | /************************************************************************* |
54 | | // linux/386 (generic "execve" format) |
55 | | **************************************************************************/ |
56 | | |
57 | 41.4k | PackLinuxI386::PackLinuxI386(InputFile *f) : super(f), |
58 | 41.4k | ei_osabi(Elf32_Ehdr::ELFOSABI_LINUX), osabi_note(nullptr) |
59 | 41.4k | { |
60 | 41.4k | bele = &N_BELE_RTP::le_policy; |
61 | 41.4k | } |
62 | | |
63 | 13.9k | PackBSDI386::PackBSDI386(InputFile *f) : super(f) |
64 | 13.9k | { |
65 | | // Shell scripts need help specifying the target operating system. |
66 | | // Elf input will override this with .e_ident[EI_OSABI] or PT_NOTE. |
67 | | // [2006-09-27: Today's only runtime stub for shell is for linux.] |
68 | 13.9k | if (Elf32_Ehdr::ELFOSABI_LINUX==opt->o_unix.osabi0) { |
69 | | // Disallow an incompatibility. |
70 | 13.9k | ei_osabi = Elf32_Ehdr::ELFOSABI_NONE; |
71 | 13.9k | } |
72 | 0 | else { |
73 | 0 | ei_osabi = opt->o_unix.osabi0; // might be ELFOSABI_NONE |
74 | 0 | } |
75 | 13.9k | } |
76 | | |
77 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
78 | | #include "stub/i386-linux.elf.execve-entry.h" |
79 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
80 | | #include "stub/i386-linux.elf.execve-fold.h" |
81 | | |
82 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
83 | | #include "stub/i386-bsd.elf.execve-entry.h" |
84 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
85 | | #include "stub/i386-bsd.elf.execve-fold.h" |
86 | | |
87 | | |
88 | | const int *PackLinuxI386::getCompressionMethods(int method, int level) const |
89 | 0 | { |
90 | 0 | return Packer::getDefaultCompressionMethods_le32(method, level); |
91 | 0 | } |
92 | | |
93 | | const int *PackLinuxI386::getFilters() const |
94 | 0 | { |
95 | 0 | static const int filters[] = { |
96 | 0 | 0x49, 0x46, |
97 | 0 | 0x26, 0x24, 0x11, 0x14, 0x13, 0x16, 0x25, 0x15, 0x12, |
98 | | #if 0 |
99 | | // 0x80..0x87 are regarded as "untested". |
100 | | 0x83, 0x86, 0x80, 0x84, 0x87, 0x81, 0x82, 0x85, |
101 | | 0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12, |
102 | | #endif |
103 | 0 | FT_END }; |
104 | 0 | return filters; |
105 | 0 | } |
106 | | |
107 | | static void |
108 | | set_stub_brk(Elf_LE32_Phdr *const phdr1, unsigned brka) |
109 | 0 | { |
110 | 0 | #define PAGE_MASK (~0ul<<12) |
111 | | // linux-2.6.14 binfmt_elf.c: SIGKILL if (0==.p_memsz) on a page boundary |
112 | 0 | unsigned const brkb = brka | ((0==(~PAGE_MASK & brka)) ? 0x20 : 0); |
113 | 0 | phdr1->p_type = PT_LOAD; // be sure |
114 | 0 | phdr1->p_offset = ~PAGE_MASK & brkb; |
115 | 0 | phdr1->p_vaddr = brkb; |
116 | 0 | phdr1->p_paddr = brkb; |
117 | 0 | phdr1->p_filesz = 0; |
118 | 0 | phdr1->p_memsz = 0; |
119 | 0 | if (0==phdr1->p_flags) { |
120 | 0 | phdr1->p_flags = Elf32_Phdr::PF_R|Elf32_Phdr::PF_W; |
121 | 0 | } |
122 | 0 | if (0==phdr1->p_align) { |
123 | 0 | phdr1->p_align = 0x1000; |
124 | 0 | } |
125 | 0 | #undef PAGE_MASK |
126 | 0 | } |
127 | | |
128 | | void |
129 | | PackLinuxI386::generateElfHdr( |
130 | | OutputFile *fo, |
131 | | void const *proto, |
132 | | unsigned const brka |
133 | | ) |
134 | 0 | { |
135 | 0 | cprElfHdr2 *const h2 = (cprElfHdr2 *)(void *)&elfout; |
136 | 0 | cprElfHdr3 *const h3 = (cprElfHdr3 *)(void *)&elfout; |
137 | 0 | memcpy(h3, proto, sizeof(*h3)); // reads beyond, but OK |
138 | |
|
139 | 0 | assert(h2->ehdr.e_phoff == sizeof(Elf32_Ehdr)); |
140 | 0 | assert(h2->ehdr.e_shoff == 0); |
141 | 0 | assert(h2->ehdr.e_ehsize == sizeof(Elf32_Ehdr)); |
142 | 0 | assert(h2->ehdr.e_phentsize == sizeof(Elf32_Phdr)); |
143 | 0 | assert(h2->ehdr.e_shnum == 0); |
144 | | |
145 | | #if 0 //{ |
146 | | unsigned identsize; |
147 | | char const *const ident = getIdentstr(&identsize); |
148 | | #endif //} |
149 | 0 | h2->phdr[0].p_filesz = sizeof(*h2); // + identsize; |
150 | 0 | h2->phdr[0].p_memsz = h2->phdr[0].p_filesz; |
151 | | |
152 | | // Info for OS kernel to set the brk() |
153 | 0 | if (brka) { |
154 | 0 | set_stub_brk(&h2->phdr[1], brka); |
155 | 0 | } |
156 | |
|
157 | 0 | if (ph.format==UPX_F_LINUX_i386 |
158 | 0 | || ph.format==UPX_F_LINUX_SH_i386 |
159 | 0 | || ph.format==UPX_F_BSD_i386 |
160 | 0 | ) { |
161 | | // SELinux, PAx, grSecurity demand no PF_W if PF_X. |
162 | | // kernel-2.6.12-2.3.legacy_FC3 has a bug which demands |
163 | | // a PT_LOAD with PF_W, else SIGSEGV when clearing page fragment |
164 | | // on low page of ".bss", which is the high page of .text. |
165 | | // So the minimum number of PT_LOAD is 2. |
166 | 0 | assert(h2->ehdr.e_phnum==2); |
167 | 0 | memset(&h2->linfo, 0, sizeof(h2->linfo)); |
168 | 0 | fo->write(h2, sizeof(*h2)); |
169 | 0 | } |
170 | 0 | else if (ph.format==UPX_F_LINUX_ELFI_i386) { |
171 | 0 | assert(h3->ehdr.e_phnum==3); |
172 | 0 | memset(&h3->linfo, 0, sizeof(h3->linfo)); |
173 | 0 | fo->write(h3, sizeof(*h3)); |
174 | 0 | } |
175 | 0 | else { |
176 | 0 | assert(false); // unknown ph.format, PackUnix::generateElfHdr |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | | void |
181 | | PackLinuxI386::pack1(OutputFile *fo, Filter &) |
182 | 0 | { |
183 | | // create a pseudo-unique program id for our paranoid stub |
184 | 0 | progid = getRandomId(); |
185 | |
|
186 | 0 | generateElfHdr(fo, stub_i386_linux_elf_execve_fold, 0); |
187 | 0 | } |
188 | | |
189 | | void |
190 | | PackBSDI386::pack1(OutputFile *fo, Filter &) |
191 | 0 | { |
192 | | // create a pseudo-unique program id for our paranoid stub |
193 | 0 | progid = getRandomId(); |
194 | |
|
195 | 0 | generateElfHdr(fo, stub_i386_bsd_elf_execve_fold, 0); |
196 | 0 | } |
197 | | |
198 | | void |
199 | | PackLinuxI386::pack4(OutputFile *fo, Filter &ft) |
200 | 0 | { |
201 | 0 | overlay_offset = sizeof(elfout.ehdr) + |
202 | 0 | (elfout.ehdr.e_phentsize * elfout.ehdr.e_phnum) + |
203 | 0 | sizeof(l_info) + |
204 | 0 | ((elfout.ehdr.e_phnum==3) ? (unsigned) elfout.phdr[2].p_memsz : 0) ; |
205 | 0 | unsigned nw = fo->getBytesWritten(); |
206 | 0 | elfout.phdr[0].p_filesz = nw; |
207 | 0 | nw = 0u-((0u-elfout.phdr[0].p_align) & (0u-nw)); // ALIGN_UP |
208 | 0 | super::pack4(fo, ft); // write PackHeader and overlay_offset |
209 | 0 | set_stub_brk(&elfout.phdr[1], nw + elfout.phdr[0].p_vaddr); |
210 | |
|
211 | | #if 0 // { |
212 | | // /usr/bin/strip from RedHat 8.0 (binutils-2.13.90.0.2-2) |
213 | | // generates a 92-byte [only] output, because the "linking view" |
214 | | // is empty. This code supplies a "linking view". |
215 | | // However, 'strip' then generates _plausible_ junk that gets |
216 | | // "Illegal instruction" because 'strip' changes p_hdr[1].p_align, |
217 | | // .p_offset, and .p_vaddr incorrectly. So the "cure" is worse than |
218 | | // the disease. It is obvious that a 92-byte file is bad, |
219 | | // but it is not obvious that the changed .p_align is bad. |
220 | | // Also, having a totally empty "linking view" is easier for 'strip' |
221 | | // to fix: just detect that, and do nothing. |
222 | | // So, we don't use this code for now [2003-01-11]. |
223 | | |
224 | | // Supply a "linking view" that covers everything, |
225 | | // so that 'strip' does not omit everything. |
226 | | Elf_LE32_Shdr shdr; |
227 | | // The section header string table. |
228 | | char const shstrtab[] = "\0.\0.shstrtab"; |
229 | | |
230 | | unsigned eod = elfout.phdr[0].p_filesz; |
231 | | elfout.ehdr.e_shoff = eod; |
232 | | elfout.ehdr.e_shentsize = sizeof(shdr); |
233 | | elfout.ehdr.e_shnum = 3; |
234 | | elfout.ehdr.e_shstrndx = 2; |
235 | | |
236 | | // An empty Elf32_Shdr for space as a null index. |
237 | | memset(&shdr, 0, sizeof(shdr)); |
238 | | shdr.sh_type = Elf32_Shdr::SHT_NULL; |
239 | | fo->write(&shdr, sizeof(shdr)); |
240 | | |
241 | | // Cover all the bits we need at runtime. |
242 | | memset(&shdr, 0, sizeof(shdr)); |
243 | | shdr.sh_name = 1; |
244 | | shdr.sh_type = Elf32_Shdr::SHT_PROGBITS; |
245 | | shdr.sh_flags = Elf32_Shdr::SHF_ALLOC; |
246 | | shdr.sh_addr = elfout.phdr[0].p_vaddr; |
247 | | shdr.sh_offset = overlay_offset; |
248 | | shdr.sh_size = eod - overlay_offset; |
249 | | shdr.sh_addralign = 4096; |
250 | | fo->write(&shdr, sizeof(shdr)); |
251 | | |
252 | | // A section header for the section header string table. |
253 | | memset(&shdr, 0, sizeof(shdr)); |
254 | | shdr.sh_name = 3; |
255 | | shdr.sh_type = Elf32_Shdr::SHT_STRTAB; |
256 | | shdr.sh_offset = 3*sizeof(shdr) + eod; |
257 | | shdr.sh_size = sizeof(shstrtab); |
258 | | fo->write(&shdr, sizeof(shdr)); |
259 | | |
260 | | fo->write(shstrtab, sizeof(shstrtab)); |
261 | | #endif // } |
262 | | |
263 | | |
264 | | // Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel |
265 | | // tries to make .bss, which requires PF_W. |
266 | | // But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X. |
267 | | #if 0 /*{*/ |
268 | | #undef PAGE_MASK |
269 | | #define PAGE_MASK (~0u<<12) |
270 | | // pre-calculate for benefit of runtime disappearing act via munmap() |
271 | | elfout.phdr[0].p_memsz = PAGE_MASK & (~PAGE_MASK + elfout.phdr[0].p_filesz); |
272 | | #undef PAGE_MASK |
273 | | #else /*}{*/ |
274 | 0 | elfout.phdr[0].p_memsz = elfout.phdr[0].p_filesz; |
275 | 0 | #endif /*}*/ |
276 | | |
277 | | // rewrite Elf header |
278 | 0 | fo->seek(0, SEEK_SET); |
279 | 0 | fo->rewrite(&elfout, overlay_offset); |
280 | 0 | } |
281 | | |
282 | | Linker *PackLinuxI386::newLinker() const |
283 | 0 | { |
284 | 0 | return new ElfLinkerX86; |
285 | 0 | } |
286 | | |
287 | | void |
288 | | PackLinuxI386::buildLinuxLoader( |
289 | | upx_byte const *const proto, |
290 | | unsigned const szproto, |
291 | | upx_byte const *const fold, |
292 | | unsigned const szfold, |
293 | | Filter const *ft |
294 | | ) |
295 | 0 | { |
296 | 0 | initLoader(proto, szproto); |
297 | |
|
298 | 0 | unsigned fold_hdrlen = 0; |
299 | 0 | if (0 < szfold) { |
300 | 0 | cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold; |
301 | 0 | fold_hdrlen = usizeof(hf->ehdr) + hf->ehdr.e_phentsize * hf->ehdr.e_phnum + |
302 | 0 | usizeof(l_info); |
303 | 0 | if (0 == get_le32(fold_hdrlen + fold)) { |
304 | | // inconsistent SIZEOF_HEADERS in *.lds (ld, binutils) |
305 | 0 | fold_hdrlen = upx::umax(0x80u, fold_hdrlen); |
306 | 0 | } |
307 | 0 | } |
308 | | // This adds the definition to the "library", to be used later. |
309 | | // NOTE: the stub is NOT compressed! The savings is not worth it. |
310 | 0 | linker->addSection("FOLDEXEC", fold + fold_hdrlen, szfold - fold_hdrlen, 0); |
311 | |
|
312 | 0 | n_mru = ft->n_mru; |
313 | | |
314 | | // Rely on "+80CXXXX" [etc] in getDecompressorSections() packer_c.cpp */ |
315 | | // // Here is a quick summary of the format of the output file: |
316 | | // linker->setLoaderAlignOffset( |
317 | | // // Elf32_Edhr |
318 | | // sizeof(elfout.ehdr) + |
319 | | // // Elf32_Phdr: 1 for exec86, 2 for sh86, 3 for elf86 |
320 | | // (elfout.ehdr.e_phentsize * elfout.ehdr.e_phnum) + |
321 | | // // checksum UPX! lsize version format |
322 | | // sizeof(l_info) + |
323 | | // // PT_DYNAMIC with DT_NEEDED "forwarded" from original file |
324 | | // ((elfout.ehdr.e_phnum==3) ? (unsigned) elfout.phdr[2].p_memsz : 0) + |
325 | | // // p_progid, p_filesize, p_blocksize |
326 | | // sizeof(p_info) + |
327 | | // // compressed data |
328 | | // b_len + ph.c_len ); |
329 | | // // entry to stub |
330 | 0 | addLoader("LEXEC000", nullptr); |
331 | |
|
332 | 0 | if (ft->id) { |
333 | 0 | if (n_mru) { |
334 | 0 | addLoader("LEXEC009", nullptr); |
335 | 0 | } |
336 | 0 | } |
337 | 0 | addLoader("LEXEC010", nullptr); |
338 | 0 | linker->defineSymbol("filter_cto", ft->cto); |
339 | 0 | linker->defineSymbol("filter_length", |
340 | 0 | (ft->id & 0xf) % 3 == 0 ? ft->calls : |
341 | 0 | ft->lastcall - ft->calls * 4); |
342 | 0 | addLoader(getDecompressorSections(), nullptr); |
343 | 0 | addLoader("LEXEC015", nullptr); |
344 | 0 | if (ft->id) { |
345 | 0 | { // decompr, unfilter not separate |
346 | 0 | if (0x80==(ft->id & 0xF0)) { |
347 | 0 | addLoader("LEXEC110", nullptr); |
348 | 0 | if (n_mru) { |
349 | 0 | addLoader("LEXEC100", nullptr); |
350 | 0 | } |
351 | | // bug in APP: jmp and label must be in same .asx/.asy |
352 | 0 | addLoader("LEXEC016", nullptr); |
353 | 0 | } |
354 | 0 | } |
355 | 0 | addFilter32(ft->id); |
356 | 0 | { // decompr always unfilters |
357 | 0 | addLoader("LEXEC017", nullptr); |
358 | 0 | } |
359 | 0 | } |
360 | 0 | else { |
361 | 0 | addLoader("LEXEC017", nullptr); |
362 | 0 | } |
363 | |
|
364 | 0 | addLoader("IDENTSTR", nullptr); |
365 | 0 | addLoader("LEXEC020", nullptr); |
366 | 0 | addLoader("FOLDEXEC", nullptr); |
367 | 0 | if (M_IS_LZMA(ph.method)) { |
368 | 0 | const lzma_compress_result_t *res = &ph.compress_result.result_lzma; |
369 | 0 | upx_uint32_t properties = // lc, lp, pb, dummy |
370 | 0 | (res->lit_context_bits << 0) | |
371 | 0 | (res->lit_pos_bits << 8) | |
372 | 0 | (res->pos_bits << 16); |
373 | 0 | if (bele->isBE()) // big endian - bswap32 |
374 | 0 | properties = bswap32(properties); |
375 | 0 | linker->defineSymbol("lzma_properties", properties); |
376 | | |
377 | | // These lengths assume only one block (typ. 524288 bytes: 0.5 MiB). |
378 | | // i386 handles more than one block, and computes the lengths |
379 | | // dynamically from struct b_info. Why do others need these? |
380 | 0 | if (linker->findSymbol("lzma_c_len", false)) { |
381 | | // -2 for properties |
382 | 0 | linker->defineSymbol("lzma_c_len", ph.c_len - 2); |
383 | 0 | } |
384 | 0 | if (linker->findSymbol("lzma_u_len", false)) { |
385 | 0 | linker->defineSymbol("lzma_u_len", ph.c_len); |
386 | 0 | } |
387 | |
|
388 | 0 | unsigned const stack = getDecompressorWrkmemSize(); |
389 | 0 | linker->defineSymbol("lzma_stack_adjust", 0u - stack); |
390 | 0 | } |
391 | 0 | if (0x80==(ft->id & 0xF0)) { |
392 | 0 | int const mru = ft->n_mru ? 1+ ft->n_mru : 0; |
393 | 0 | if (mru && mru!=256) { |
394 | 0 | unsigned const is_pwr2 = (0==((mru -1) & mru)); |
395 | 0 | linker->defineSymbol("NMRU", mru - is_pwr2); |
396 | 0 | } |
397 | 0 | } |
398 | 0 | relocateLoader(); |
399 | 0 | } |
400 | | |
401 | | void |
402 | | PackLinuxI386::buildLoader(Filter const *ft) |
403 | 0 | { |
404 | 0 | unsigned const sz_fold = sizeof(stub_i386_linux_elf_execve_fold); |
405 | 0 | MemBuffer buf(sz_fold); |
406 | 0 | memcpy(buf, stub_i386_linux_elf_execve_fold, sz_fold); |
407 | | |
408 | | // patch loader |
409 | | // note: we only can use /proc/<pid>/fd when exetype > 0. |
410 | | // also, we sleep much longer when compressing a script. |
411 | 0 | checkPatch(nullptr, 0, 0, 0); // reset |
412 | 0 | patch_le32(buf,sz_fold,"UPX4",exetype > 0 ? 3 : 15); // sleep time |
413 | 0 | patch_le32(buf,sz_fold,"UPX3",progid); |
414 | 0 | patch_le32(buf,sz_fold,"UPX2",exetype > 0 ? 0 : 0x7fffffff); |
415 | |
|
416 | 0 | buildLinuxLoader( |
417 | 0 | stub_i386_linux_elf_execve_entry, sizeof(stub_i386_linux_elf_execve_entry), |
418 | 0 | buf, sz_fold, ft ); |
419 | 0 | } |
420 | | |
421 | | void |
422 | | PackBSDI386::buildLoader(Filter const *ft) |
423 | 0 | { |
424 | 0 | unsigned const sz_fold = sizeof(stub_i386_bsd_elf_execve_fold); |
425 | 0 | MemBuffer buf(sz_fold); |
426 | 0 | memcpy(buf, stub_i386_bsd_elf_execve_fold, sz_fold); |
427 | | |
428 | | // patch loader |
429 | | // note: we only can use /proc/<pid>/fd when exetype > 0. |
430 | | // also, we sleep much longer when compressing a script. |
431 | 0 | checkPatch(nullptr, 0, 0, 0); // reset |
432 | 0 | patch_le32(buf,sz_fold,"UPX4",exetype > 0 ? 3 : 15); // sleep time |
433 | 0 | patch_le32(buf,sz_fold,"UPX3",progid); |
434 | 0 | patch_le32(buf,sz_fold,"UPX2",exetype > 0 ? 0 : 0x7fffffff); |
435 | |
|
436 | 0 | buildLinuxLoader( |
437 | 0 | stub_i386_bsd_elf_execve_entry, sizeof(stub_i386_bsd_elf_execve_entry), |
438 | 0 | buf, sz_fold, ft ); |
439 | 0 | } |
440 | | |
441 | | // FIXME: getLoaderPrefixSize is unused? |
442 | | int PackLinuxI386::getLoaderPrefixSize() const |
443 | 0 | { |
444 | 0 | return 116; |
445 | 0 | } |
446 | | |
447 | | |
448 | | /************************************************************************* |
449 | | // some ELF utility functions |
450 | | **************************************************************************/ |
451 | | |
452 | | // basic check of a Linux ELF Ehdr |
453 | | int PackLinuxI386::checkEhdr(const Elf_LE32_Ehdr *ehdr) const |
454 | 0 | { |
455 | 0 | const unsigned char * const buf = ehdr->e_ident; |
456 | |
|
457 | 0 | if (memcmp(buf, "\x7f\x45\x4c\x46\x01\x01\x01", 7)) // ELF 32-bit LSB |
458 | 0 | return -1; |
459 | | |
460 | | // now check the ELF header |
461 | 0 | if (!memcmp(buf+8, "FreeBSD", 7)) // branded |
462 | 0 | return 1; |
463 | 0 | if (ehdr->e_type != Elf32_Ehdr::ET_EXEC |
464 | 0 | && ehdr->e_type != Elf32_Ehdr::ET_DYN ) // executable |
465 | 0 | return 2; |
466 | 0 | if (ehdr->e_machine != Elf32_Ehdr::EM_386) // Intel 80386 |
467 | 0 | return 3; |
468 | 0 | if (ehdr->e_version != Elf32_Ehdr::EV_CURRENT) // version |
469 | 0 | return 4; |
470 | 0 | if (ehdr->e_phnum < 1) |
471 | 0 | return 5; |
472 | 0 | if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) |
473 | 0 | return 6; |
474 | | |
475 | | // check for Linux kernels |
476 | 0 | if (ehdr->e_entry == 0xC0100000) // uncompressed vmlinux |
477 | 0 | return 1000; |
478 | 0 | if (ehdr->e_entry == 0x00001000) // compressed vmlinux |
479 | 0 | return 1001; |
480 | 0 | if (ehdr->e_entry == 0x00100000) // compressed bvmlinux |
481 | 0 | return 1002; |
482 | | |
483 | | // FIXME: add more checks for kernels |
484 | | |
485 | | // FIXME: add special checks for other ELF i386 formats, like |
486 | | // NetBSD, OpenBSD, Solaris, .... |
487 | | |
488 | | // success |
489 | 0 | return 0; |
490 | 0 | } |
491 | | |
492 | | |
493 | | |
494 | | /************************************************************************* |
495 | | // |
496 | | **************************************************************************/ |
497 | | |
498 | | tribool PackLinuxI386::canPack() |
499 | 0 | { |
500 | 0 | if (exetype != 0) |
501 | 0 | return super::canPack(); |
502 | | |
503 | 0 | Elf_LE32_Ehdr ehdr; |
504 | 0 | unsigned char *buf = ehdr.e_ident; |
505 | |
|
506 | 0 | fi->seek(0, SEEK_SET); |
507 | 0 | fi->readx(&ehdr, sizeof(ehdr)); |
508 | 0 | fi->seek(0, SEEK_SET); |
509 | |
|
510 | 0 | exetype = 0; |
511 | 0 | const unsigned l = get_le32(buf); |
512 | |
|
513 | 0 | int elf = checkEhdr(&ehdr); |
514 | 0 | if (elf >= 0) { |
515 | | // NOTE: ELF executables are now handled by p_lx_elf.cpp, |
516 | | // so we only handle them here if force_execve |
517 | 0 | if (elf == 0 && opt->o_unix.force_execve) { |
518 | 0 | exetype = 1; |
519 | |
|
520 | 0 | unsigned osabi0 = ehdr.e_ident[Elf32_Ehdr::EI_OSABI]; |
521 | 0 | switch (osabi0) { |
522 | 0 | case Elf32_Ehdr::ELFOSABI_LINUX: |
523 | 0 | case Elf32_Ehdr::ELFOSABI_FREEBSD: |
524 | 0 | case Elf32_Ehdr::ELFOSABI_NETBSD: |
525 | 0 | case Elf32_Ehdr::ELFOSABI_OPENBSD: |
526 | 0 | ei_osabi = osabi0; // Proudly declares its osabi in Ehdr. |
527 | 0 | break; |
528 | 0 | default: |
529 | 0 | unsigned const e_phnum = get_te16(&ehdr.e_phnum); |
530 | 0 | if (e_phnum<=(512/sizeof(Elf32_Phdr))) { |
531 | 0 | union { |
532 | 0 | unsigned char buf2[512]; |
533 | | //Elf32_Phdr phdr; |
534 | 0 | } u; |
535 | 0 | fi->seek(get_te32(&ehdr.e_phoff), SEEK_SET); |
536 | 0 | fi->readx(u.buf2, sizeof(u.buf2)); |
537 | 0 | fi->seek(0, SEEK_SET); |
538 | 0 | Elf32_Phdr const *phdr = (Elf32_Phdr *) u.buf2; |
539 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
540 | 0 | if (phdr->PT_NOTE == get_te32(&phdr->p_type)) { |
541 | 0 | unsigned const offset = get_te32(&phdr->p_offset); |
542 | 0 | struct Elf32_Note note; memset(¬e, 0, sizeof(note)); |
543 | 0 | fi->seek(offset, SEEK_SET); |
544 | 0 | fi->readx(¬e, sizeof(note)); |
545 | 0 | fi->seek(0, SEEK_SET); |
546 | 0 | if (4==get_te32(¬e.descsz) |
547 | 0 | && 1==get_te32(¬e.type) |
548 | 0 | && 0==note.end ) { |
549 | 0 | if (0==strcmp("NetBSD", (char const *)note.text)) { |
550 | 0 | ei_osabi = Elf32_Ehdr::ELFOSABI_NETBSD; |
551 | 0 | break; |
552 | 0 | } |
553 | 0 | if (0==strcmp("OpenBSD", (char const *)note.text)) { |
554 | 0 | ei_osabi = Elf32_Ehdr::ELFOSABI_OPENBSD; |
555 | 0 | break; |
556 | 0 | } |
557 | 0 | } |
558 | 0 | } |
559 | 0 | } |
560 | 0 | } |
561 | 0 | } |
562 | 0 | } |
563 | 0 | if (UPX_F_BSD_i386==getFormat() |
564 | 0 | && !(Elf32_Ehdr::ELFOSABI_FREEBSD==ei_osabi |
565 | 0 | || Elf32_Ehdr::ELFOSABI_NETBSD ==ei_osabi |
566 | 0 | || Elf32_Ehdr::ELFOSABI_OPENBSD==ei_osabi )) { |
567 | 0 | return false; |
568 | 0 | } |
569 | 0 | } |
570 | 0 | else if (l == 0x00640107 || l == 0x00640108 || l == 0x0064010b || l == 0x006400cc) |
571 | 0 | { |
572 | | // OMAGIC / NMAGIC / ZMAGIC / QMAGIC |
573 | 0 | exetype = 2; |
574 | | // FIXME: N_TRSIZE, N_DRSIZE |
575 | | // FIXME: check for aout shared libraries |
576 | 0 | } |
577 | 0 | else { // shell scripts and other interpreters |
578 | 0 | if (Elf32_Ehdr::ELFOSABI_LINUX!=ei_osabi) { |
579 | 0 | return false; // so far, only Linux has runtime stub for shell |
580 | 0 | } |
581 | 0 | else if (!memcmp(buf, "#!/", 3)) // #!/bin/sh |
582 | 0 | exetype = -1; |
583 | 0 | else if (!memcmp(buf, "#! /", 4)) // #! /bin/sh |
584 | 0 | exetype = -1; |
585 | 0 | else if (!memcmp(buf, "\xca\xfe\xba\xbe", 4)) // Java bytecode |
586 | 0 | exetype = -2; |
587 | 0 | } |
588 | | |
589 | 0 | return super::canPack(); |
590 | 0 | } |
591 | | |
592 | | |
593 | 0 | void PackLinuxI386::patchLoader() { } |
594 | | |
595 | | |
596 | | void PackLinuxI386::patchLoaderChecksum() |
597 | 0 | { |
598 | 0 | unsigned char *const ptr = getLoader(); |
599 | 0 | l_info *const lp = (l_info *)(sizeof(elfout.ehdr) + |
600 | 0 | (elfout.ehdr.e_phnum * elfout.ehdr.e_phentsize) + (char *)&elfout ); |
601 | | // checksum for loader + p_info |
602 | 0 | lp->l_checksum = 0; |
603 | 0 | lp->l_magic = UPX_ELF_MAGIC; |
604 | 0 | set_te16(&lp->l_lsize, (upx_uint16_t) lsize); |
605 | 0 | lp->l_version = (unsigned char) ph.version; |
606 | 0 | lp->l_format = (unsigned char) ph.format; |
607 | | // INFO: lp->l_checksum is currently unused |
608 | 0 | set_te32(&lp->l_checksum, upx_adler32(ptr, lsize)); |
609 | 0 | } |
610 | | |
611 | | |
612 | | void PackLinuxI386::updateLoader(OutputFile *fo) |
613 | 0 | { |
614 | 0 | elfout.ehdr.e_entry = fo->getBytesWritten() + elfout.phdr[0].p_vaddr; |
615 | 0 | } |
616 | | |
617 | | /* vim:set ts=4 sw=4 et: */ |