/src/upx/src/p_lx_elf.cpp
Line | Count | Source |
1 | | /* p_lx_elf.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) 2000-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 | | #define ALLOW_INT_PLUS_MEMBUFFER 1 |
34 | | #include "conf.h" |
35 | | |
36 | | #include "file.h" |
37 | | #include "filter.h" |
38 | | #include "linker.h" |
39 | | #include "packer.h" |
40 | | #include "p_elf.h" |
41 | | #include "p_unix.h" |
42 | | #include "p_lx_exc.h" |
43 | | #include "p_lx_elf.h" |
44 | | #include "ui.h" |
45 | | |
46 | | // NOLINTBEGIN(clang-analyzer-core.CallAndMessage) |
47 | | // NOLINTBEGIN(clang-analyzer-deadcode.DeadStores) |
48 | | |
49 | | #if defined(__CHERI__) && defined(__CHERI_PURE_CAPABILITY__) |
50 | | # pragma clang diagnostic ignored "-Wcheri-capability-misuse" // TODO later |
51 | | # pragma clang diagnostic ignored "-Wcheri-provenance" // TODO later |
52 | | #endif |
53 | | |
54 | | using upx::umin; |
55 | | |
56 | 323k | #define PT_LOAD Elf32_Phdr::PT_LOAD /* 64-bit PT_LOAD is the same */ |
57 | 0 | #define PT_NOTE32 Elf32_Phdr::PT_NOTE |
58 | 0 | #define PT_NOTE64 Elf64_Phdr::PT_NOTE |
59 | 0 | #define PT_GNU_STACK32 Elf32_Phdr::PT_GNU_STACK |
60 | 0 | #define PT_GNU_STACK64 Elf64_Phdr::PT_GNU_STACK |
61 | 0 | #define PT_GNU_RELRO32 Elf32_Phdr::PT_GNU_RELRO |
62 | 0 | #define PT_GNU_RELRO64 Elf64_Phdr::PT_GNU_RELRO |
63 | | |
64 | | // also see stub/src/MAX_ELF_HDR.[Sc] |
65 | | static constexpr unsigned MAX_ELF_HDR_32 = 512; |
66 | | static constexpr unsigned MAX_ELF_HDR_64 = 1024; |
67 | | |
68 | | //static unsigned const EF_ARM_HASENTRY = 0x02; |
69 | | static unsigned const EF_ARM_EABI_VER4 = 0x04000000; |
70 | | static unsigned const EF_ARM_EABI_VER5 = 0x05000000; |
71 | | |
72 | | /*static*/ const unsigned char PackLinuxElf::o_shstrtab[] = { \ |
73 | | /*start*/ '\0', |
74 | | /*offset 1*/ '.','n','o','t','e','.','g','n','u','.','b','u','i','l','d','-','i','d','\0', |
75 | | /*offset 20*/ '.','s','h','s','t','r','t','a','b','\0' |
76 | | }; |
77 | | |
78 | | static unsigned |
79 | | up4(unsigned x) |
80 | 500 | { |
81 | 500 | return ~3u & (3+ x); |
82 | 500 | } |
83 | | |
84 | | static unsigned |
85 | | up8(unsigned x) |
86 | 0 | { |
87 | 0 | return ~7u & (7+ x); |
88 | 0 | } |
89 | | |
90 | | static off_t |
91 | | fpadN(OutputFile *fo, unsigned len) |
92 | 0 | { |
93 | 0 | if (len) { |
94 | 0 | MemBuffer pad(len); pad.clear(); |
95 | 0 | fo->write(pad, len); |
96 | 0 | } |
97 | 0 | return fo->st_size(); |
98 | 0 | } |
99 | | |
100 | | static off_t |
101 | | fpad4(OutputFile *fo, unsigned pos) |
102 | 0 | { |
103 | 0 | (void)pos; // debug: compare 'pos' with "shell grep pos /proc/PID/fdinfo/FD" |
104 | 0 | if (!fo) { // --test, --list |
105 | 0 | return 0; |
106 | 0 | } |
107 | 0 | off_t len = fo->st_size(); |
108 | 0 | unsigned d = 3u & (0 - len); |
109 | 0 | if (d) { |
110 | 0 | unsigned zero = 0; |
111 | 0 | fo->write(&zero, d); |
112 | 0 | } |
113 | 0 | return d + len; |
114 | 0 | } |
115 | | |
116 | | static off_t |
117 | | fpad8(OutputFile *fo, unsigned pos) |
118 | 0 | { |
119 | 0 | (void)pos; // debug: compare 'pos' with "shell grep pos /proc/PID/fdinfo/FD" |
120 | 0 | if (!fo) { // --test, --list |
121 | 0 | return 0; |
122 | 0 | } |
123 | 0 | off_t len = fo->st_size(); |
124 | 0 | unsigned d = 7u & (0 - len); |
125 | 0 | if (d) { |
126 | 0 | upx_uint64_t zero = 0; |
127 | 0 | fo->write(&zero, d); |
128 | 0 | } |
129 | 0 | return d + len; |
130 | 0 | } |
131 | | |
132 | | static unsigned |
133 | | funpad4(InputFile *fi) |
134 | 134 | { |
135 | 134 | unsigned d = 3u & (0 - fi->tell()); |
136 | 134 | if (d) |
137 | 131 | fi->seek(d, SEEK_CUR); |
138 | 134 | return d; |
139 | 134 | } |
140 | | |
141 | | static void alloc_file_image(MemBuffer &mb, off_t size) |
142 | 23.6k | { |
143 | 23.6k | assert(mem_size_valid_bytes(size)); |
144 | 23.6k | if (mb.getVoidPtr() == nullptr) { |
145 | 22.5k | mb.alloc(size); |
146 | 22.5k | } else { |
147 | 1.08k | assert((u32_t)size <= mb.getSize()); |
148 | 1.08k | } |
149 | 23.6k | } |
150 | | |
151 | | int |
152 | | PackLinuxElf32::checkEhdr(Elf32_Ehdr const *ehdr) const |
153 | 169k | { |
154 | 169k | const unsigned char * const buf = ehdr->e_ident; |
155 | | |
156 | 169k | if (0!=memcmp(buf, "\x7f\x45\x4c\x46", 4) // "\177ELF" |
157 | 85.4k | || buf[Elf32_Ehdr::EI_CLASS]!=ei_class |
158 | 40.1k | || buf[Elf32_Ehdr::EI_DATA] !=ei_data |
159 | 169k | ) { |
160 | 151k | return -1; |
161 | 151k | } |
162 | 17.2k | if (!memcmp(buf+8, "FreeBSD", 7)) // branded |
163 | 51 | return 1; |
164 | | |
165 | 17.1k | int const type = get_te16(&ehdr->e_type); |
166 | 17.1k | if (type != Elf32_Ehdr::ET_EXEC && type != Elf32_Ehdr::ET_DYN) |
167 | 2.54k | return 2; |
168 | 14.6k | if (get_te16(&ehdr->e_machine) != (unsigned) e_machine) |
169 | 5.92k | return 3; |
170 | 8.70k | if (get_te32(&ehdr->e_version) != Elf32_Ehdr::EV_CURRENT) |
171 | 1.08k | return 4; |
172 | 7.61k | if (e_phnum < 1) |
173 | 680 | return 5; |
174 | 6.93k | if (get_te16(&ehdr->e_phentsize) != sizeof(Elf32_Phdr)) |
175 | 613 | return 6; |
176 | | |
177 | 6.32k | if (type == Elf32_Ehdr::ET_EXEC) { |
178 | | // check for Linux kernels |
179 | 5.53k | unsigned const entry = get_te32(&ehdr->e_entry); |
180 | 5.53k | if (entry == 0xC0100000) // uncompressed vmlinux |
181 | 10 | return 1000; |
182 | 5.52k | if (entry == 0x00001000) // compressed vmlinux |
183 | 15 | return 1001; |
184 | 5.50k | if (entry == 0x00100000) // compressed bvmlinux |
185 | 15 | return 1002; |
186 | 5.50k | } |
187 | | |
188 | | // FIXME: add more checks for kernels |
189 | | |
190 | | // FIXME: add special checks for other ELF i386 formats, like |
191 | | // NetBSD, OpenBSD, Solaris, .... |
192 | | |
193 | | // success |
194 | 6.28k | return 0; |
195 | 6.32k | } |
196 | | |
197 | | int |
198 | | PackLinuxElf64::checkEhdr(Elf64_Ehdr const *ehdr) const |
199 | 65.2k | { |
200 | 65.2k | const unsigned char * const buf = ehdr->e_ident; |
201 | 65.2k | unsigned char osabi0 = buf[Elf32_Ehdr::EI_OSABI]; |
202 | 65.2k | if (0==osabi0) { |
203 | 25.3k | osabi0 = opt->o_unix.osabi0; |
204 | 25.3k | } |
205 | | |
206 | 65.2k | if (0!=memcmp(buf, "\x7f\x45\x4c\x46", 4) // "\177ELF" |
207 | 28.0k | || buf[Elf64_Ehdr::EI_CLASS]!=ei_class |
208 | 13.5k | || buf[Elf64_Ehdr::EI_DATA] !=ei_data |
209 | 6.80k | || osabi0!=ei_osabi |
210 | 65.2k | ) { |
211 | 60.5k | return -1; |
212 | 60.5k | } |
213 | 4.74k | if (!memcmp(buf+8, "FreeBSD", 7)) // branded |
214 | 22 | return 1; |
215 | | |
216 | 4.72k | int const type = get_te16(&ehdr->e_type); |
217 | 4.72k | if (type != Elf64_Ehdr::ET_EXEC && type != Elf64_Ehdr::ET_DYN) |
218 | 1.41k | return 2; |
219 | 3.31k | if (get_te16(&ehdr->e_machine) != (unsigned) e_machine) |
220 | 1.75k | return 3; |
221 | 1.55k | if (get_te32(&ehdr->e_version) != Elf64_Ehdr::EV_CURRENT) |
222 | 154 | return 4; |
223 | 1.40k | if (e_phnum < 1) |
224 | 5 | return 5; |
225 | 1.39k | if (get_te16(&ehdr->e_phentsize) != sizeof(Elf64_Phdr)) |
226 | 34 | return 6; |
227 | | |
228 | 1.36k | if (type == Elf64_Ehdr::ET_EXEC) { |
229 | | // check for Linux kernels |
230 | 1.06k | upx_uint64_t const entry = get_te64(&ehdr->e_entry); |
231 | 1.06k | if (entry == 0xC0100000) // uncompressed vmlinux |
232 | 3 | return 1000; |
233 | 1.05k | if (entry == 0x00001000) // compressed vmlinux |
234 | 3 | return 1001; |
235 | 1.05k | if (entry == 0x00100000) // compressed bvmlinux |
236 | 3 | return 1002; |
237 | 1.05k | } |
238 | | |
239 | | // FIXME: add more checks for kernels |
240 | | |
241 | | // FIXME: add special checks for other ELF i386 formats, like |
242 | | // NetBSD, OpenBSD, Solaris, .... |
243 | | |
244 | | // success |
245 | 1.35k | return 0; |
246 | 1.36k | } |
247 | | |
248 | | PackLinuxElf::PackLinuxElf(InputFile *f) |
249 | 241k | : super(f), e_phnum(0), dynstr(nullptr), |
250 | 241k | sz_phdrs(0), sz_elf_hdrs(0), sz_pack2(0), sz_pack2a(0), |
251 | 241k | lg2_page(12), page_size(1u<<lg2_page), is_pie(0), is_asl(0), |
252 | 241k | xct_off(0), o_binfo(0), so_slide(0), xct_va(0), jni_onload_va(0), |
253 | 241k | user_init_va(0), user_init_off(0), |
254 | 241k | e_machine(0), ei_class(0), ei_data(0), ei_osabi(0), osabi_note(nullptr), |
255 | 241k | shstrtab(nullptr), |
256 | 241k | o_elf_shnum(0) |
257 | 241k | { |
258 | 241k | memset(dt_table, 0, sizeof(dt_table)); |
259 | 241k | symnum_max = 0; |
260 | 241k | user_init_rp = nullptr; |
261 | 241k | } |
262 | | |
263 | | PackLinuxElf::~PackLinuxElf() |
264 | 241k | { |
265 | 241k | } |
266 | | |
267 | | int PackLinuxElf32::is_LOAD(Elf32_Phdr const *phdr) const |
268 | 169k | { |
269 | | // (1+ PT_LOPROC) can confuse! |
270 | 169k | return PT_LOAD == get_te32(&phdr->p_type); |
271 | 169k | } |
272 | | |
273 | | int PackLinuxElf64::is_LOAD(Elf64_Phdr const *phdr) const |
274 | 153k | { |
275 | | // (1+ PT_LOPROC) can confuse! |
276 | 153k | return PT_LOAD == get_te32(&phdr->p_type); |
277 | 153k | } |
278 | | |
279 | | void |
280 | | PackLinuxElf32::PackLinuxElf32help1(InputFile *f) |
281 | 172k | { |
282 | 172k | e_type = get_te16(&ehdri.e_type); |
283 | 172k | e_phnum = get_te16(&ehdri.e_phnum); |
284 | 172k | e_shnum = get_te16(&ehdri.e_shnum); |
285 | 172k | unsigned const e_phentsize = get_te16(&ehdri.e_phentsize); |
286 | 172k | if (memcmp((char const *)&ehdri, "\x7f\x45\x4c\x46", 4) // "\177ELF" |
287 | 89.2k | || ehdri.e_ident[Elf32_Ehdr::EI_CLASS]!=Elf32_Ehdr::ELFCLASS32 |
288 | 43.9k | || sizeof(Elf32_Phdr) != e_phentsize |
289 | 17.1k | || (Elf32_Ehdr::ELFDATA2MSB == ehdri.e_ident[Elf32_Ehdr::EI_DATA] |
290 | 3.52k | && &N_BELE_RTP::be_policy != bele) |
291 | 17.1k | || (Elf32_Ehdr::ELFDATA2LSB == ehdri.e_ident[Elf32_Ehdr::EI_DATA] |
292 | 155k | && &N_BELE_RTP::le_policy != bele)) { |
293 | 155k | e_phoff = 0; |
294 | 155k | e_shoff = 0; |
295 | 155k | sz_phdrs = 0; |
296 | 155k | return; |
297 | 155k | } |
298 | 17.0k | if (0==e_phnum) throwCantUnpack("0==e_phnum"); |
299 | 17.0k | e_phoff = get_te32(&ehdri.e_phoff); |
300 | 17.0k | unsigned const last_Phdr = e_phoff + e_phnum * usizeof(Elf32_Phdr); |
301 | 17.0k | if (last_Phdr < e_phoff // wrap-around |
302 | 16.9k | || e_phoff != sizeof(Elf32_Ehdr) // must be contiguous |
303 | 16.0k | || (unsigned long)file_size < last_Phdr) { |
304 | 954 | throwCantUnpack("bad e_phoff %#x", e_phoff); |
305 | 954 | } |
306 | 16.0k | e_shoff = get_te32(&ehdri.e_shoff); |
307 | 16.0k | e_shstrndx = get_te16(&ehdri.e_shstrndx); |
308 | 16.0k | unsigned const last_Shdr = e_shoff + e_shnum * usizeof(Elf32_Shdr); |
309 | 16.0k | if (last_Shdr < e_shoff // wrap-around |
310 | 15.6k | || (e_shnum && e_shoff < last_Phdr) |
311 | 14.0k | || (unsigned long)file_size < last_Shdr) { |
312 | 7.18k | if (opt->cmd == CMD_COMPRESS) { |
313 | 0 | throwCantUnpack("bad e_shoff %#x", e_shoff); |
314 | 0 | } |
315 | 7.18k | } |
316 | 16.0k | sz_phdrs = e_phnum * e_phentsize; |
317 | 16.0k | sz_elf_hdrs = sz_phdrs + sizeof(Elf32_Ehdr) + |
318 | 16.0k | n_phdrx * sizeof(Elf32_Phdr); // phdrx bodies later: ::generateElfHdr |
319 | | |
320 | 16.0k | if (f && Elf32_Ehdr::ET_DYN!=e_type) { |
321 | 10.5k | unsigned const len = file_size; // (sz_phdrs + e_phoff) except --preserve-build-id |
322 | 10.5k | alloc_file_image(file_image, len); |
323 | 10.5k | f->seek(0, SEEK_SET); |
324 | 10.5k | f->readx(file_image, len); |
325 | 10.5k | phdri= (Elf32_Phdr *)(e_phoff + file_image); // do not free() !! |
326 | 10.5k | } |
327 | 16.0k | if (f && Elf32_Ehdr::ET_DYN==e_type) { |
328 | | // The DT_SYMTAB has no designated length. Read the whole file. |
329 | 5.53k | alloc_file_image(file_image, file_size); |
330 | 5.53k | f->seek(0, SEEK_SET); |
331 | 5.53k | f->readx(file_image, file_size); |
332 | 5.53k | phdri= (Elf32_Phdr *)(e_phoff + file_image); // do not free() !! |
333 | 5.53k | if (opt->cmd != CMD_COMPRESS || !e_shoff || file_size < e_shoff) { |
334 | 5.53k | shdri = nullptr; |
335 | 5.53k | } |
336 | 0 | else { // FIXME: copy from file_image ? |
337 | 0 | fi->seek(e_shoff, SEEK_SET); |
338 | 0 | if (mb_shdr.getSize() != sizeof(Elf32_Shdr) * e_shnum) { |
339 | 0 | mb_shdr.alloc( sizeof(Elf32_Shdr) * e_shnum); |
340 | 0 | } |
341 | 0 | shdri = (Elf32_Shdr *)mb_shdr.getVoidPtr(); |
342 | 0 | fi->readx(shdri, sizeof(Elf32_Shdr) * e_shnum); |
343 | 0 | } |
344 | 5.53k | sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM); |
345 | 5.53k | if (sec_dynsym) { |
346 | 0 | unsigned t = get_te32(&sec_dynsym->sh_link); |
347 | 0 | if (e_shnum <= t) |
348 | 0 | throwCantPack("bad dynsym->sh_link"); |
349 | 0 | sec_dynstr = &shdri[t]; |
350 | 0 | } |
351 | | |
352 | 5.53k | Elf32_Phdr const *phdr= phdri; |
353 | 65.4k | for (int j = e_phnum; --j>=0; ++phdr) |
354 | 59.9k | if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { |
355 | 4.22k | unsigned offset = check_pt_dynamic(phdr); |
356 | 4.22k | dynseg= (Elf32_Dyn *)(offset + file_image); |
357 | 4.22k | invert_pt_dynamic(dynseg, |
358 | 4.22k | umin(get_te32(&phdr->p_filesz), (unsigned)(file_size_u - offset))); |
359 | 4.22k | } |
360 | 55.6k | else if (is_LOAD(phdr)) { |
361 | 6.59k | check_pt_load(phdr); |
362 | 6.59k | } |
363 | | // elf_find_dynamic() returns 0 if 0==dynseg. |
364 | 5.53k | dynstr = (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB); |
365 | 5.53k | dynsym = (Elf32_Sym /*const*/ *)elf_find_dynamic(Elf32_Dyn::DT_SYMTAB); |
366 | 5.53k | gashtab = (unsigned const *)elf_find_dynamic(Elf32_Dyn::DT_GNU_HASH); |
367 | 5.53k | hashtab = (unsigned const *)elf_find_dynamic(Elf32_Dyn::DT_HASH); |
368 | 5.53k | if (3& ((upx_uintptr_t)dynsym | (upx_uintptr_t)gashtab | (upx_uintptr_t)hashtab)) { |
369 | 19 | throwCantPack("unaligned DT_SYMTAB, DT_GNU_HASH, or DT_HASH/n"); |
370 | 19 | } |
371 | 5.51k | jni_onload_sym = elf_lookup("JNI_OnLoad"); |
372 | 5.51k | if (jni_onload_sym) { |
373 | 32 | jni_onload_va = get_te32(&jni_onload_sym->st_value); |
374 | 32 | jni_onload_va = 0; // FIXME not understood; need example |
375 | 32 | } |
376 | 5.51k | } |
377 | 16.0k | } |
378 | | |
379 | | #define WANT_EHDR_ENUM |
380 | | #define WANT_REL_ENUM |
381 | | #include "p_elf_enum.h" |
382 | | #undef WANT_REL_ENUM |
383 | | #undef WANT_EHDR_ENUM |
384 | | |
385 | | off_t PackLinuxElf::pack3(OutputFile *fo, Filter &ft) // return length of output |
386 | 0 | { |
387 | 0 | if (!fo) { |
388 | 0 | return 0; |
389 | 0 | } |
390 | 0 | unsigned disp; |
391 | 0 | unsigned len = sz_pack2a; // after headers and all PT_LOAD |
392 | |
|
393 | 0 | unsigned const t = (4 & len) ^ ((!!xct_off)<<2); // 0 or 4 |
394 | 0 | if (t) { |
395 | 0 | if (fo) { |
396 | 0 | unsigned const zero = 0; |
397 | 0 | fo->write(&zero, t); |
398 | 0 | } |
399 | 0 | len += t; // force sz_pack2 (0 mod 8) [see below] |
400 | 0 | } |
401 | |
|
402 | 0 | set_te32(&disp, sz_elf_hdrs + usizeof(p_info) + usizeof(l_info) + |
403 | 0 | (!!xct_off & !!is_asl)); // |1 iff android shlib |
404 | 0 | fo->write(&disp, sizeof(disp)); // offset(b_info) |
405 | | // FIXME: If is_shlib then that is useful only for the is_asl bit. |
406 | | // Better info is the word below with (overlay_offset - sizeof(linfo)). |
407 | |
|
408 | 0 | len += sizeof(disp); |
409 | 0 | set_te32(&disp, len); // distance back to beginning (detect dynamic reloc) |
410 | 0 | fo->write(&disp, sizeof(disp)); |
411 | 0 | len += sizeof(disp); |
412 | |
|
413 | 0 | if (xct_off) { // is_shlib |
414 | 0 | upx_uint64_t const firstpc_va = (jni_onload_va |
415 | 0 | ? jni_onload_va |
416 | 0 | : user_init_va); |
417 | 0 | set_te32(&disp, firstpc_va - load_va); |
418 | 0 | fo->write(&disp, sizeof(disp)); // DT_INIT.d_val or DT_INIT_ARRAY[0] |
419 | 0 | len += sizeof(disp); |
420 | |
|
421 | 0 | set_te32(&disp, xct_off); |
422 | 0 | fo->write(&disp, sizeof(disp)); // offset(lowest_executable_instr) |
423 | 0 | len += sizeof(disp); |
424 | |
|
425 | 0 | if (is_asl) { |
426 | 0 | xct_off += asl_delta; // the extra page |
427 | 0 | } |
428 | 0 | set_te32(&disp, overlay_offset - sizeof(linfo)); |
429 | 0 | fo->write(&disp, sizeof(disp)); // &{l_info; p_info; b_info} |
430 | 0 | len += sizeof(disp); |
431 | 0 | } |
432 | 0 | total_out += len - sz_pack2a; |
433 | 0 | sz_pack2 = len; // 0 mod 8 [see above] |
434 | | |
435 | | // FIXME: debugging aid: entry to decompressor |
436 | 0 | if (lowmem.getSize()) { |
437 | 0 | Elf32_Ehdr *const ehdr = (Elf32_Ehdr *)&lowmem[0]; |
438 | 0 | set_te32(&ehdr->e_entry, sz_pack2); // hint for decompressor |
439 | 0 | } |
440 | | // end debugging aid |
441 | |
|
442 | 0 | super::pack3(fo, ft); // append the decompressor |
443 | 0 | set_te16(&linfo.l_lsize, up4( // MATCH03: up4 |
444 | 0 | get_te16(&linfo.l_lsize) + len - sz_pack2a)); |
445 | 0 | total_out = fpad4(fo, total_out); // MATCH03 |
446 | 0 | return total_out; |
447 | 0 | } |
448 | | |
449 | | static unsigned |
450 | | is_pow2(u64_t x) |
451 | 42.1k | { |
452 | 42.1k | return !((-1+ x) & x); |
453 | 42.1k | } |
454 | | |
455 | | Elf32_Phdr const * |
456 | | PackLinuxElf32::elf_find_Phdr_for_va(upx_uint32_t addr, Elf32_Phdr const *phdr, unsigned phnum) |
457 | 19.2k | { |
458 | 57.4k | for (unsigned j = 0; j < phnum; ++j, ++phdr) { |
459 | 57.2k | u32_t align = get_te32(&phdr->p_align); |
460 | 57.2k | if (is_LOAD(phdr) |
461 | 24.2k | && is_pow2(align) && !((-1+ align) & |
462 | 23.0k | (get_te32(&phdr->p_vaddr) ^ get_te32(&phdr->p_offset))) |
463 | 21.9k | && (addr - get_te32(&phdr->p_vaddr)) < get_te32(&phdr->p_filesz)) { |
464 | 19.0k | return phdr; |
465 | 19.0k | } |
466 | 57.2k | } |
467 | 231 | return nullptr; |
468 | 19.2k | } |
469 | | |
470 | | Elf64_Phdr const * |
471 | | PackLinuxElf64::elf_find_Phdr_for_va(upx_uint64_t addr, Elf64_Phdr const *phdr, unsigned phnum) |
472 | 13.4k | { |
473 | 55.8k | for (unsigned j = 0; j < phnum; ++j, ++phdr) { |
474 | 55.5k | u64_t align = get_te64(&phdr->p_align); |
475 | 55.5k | if (is_LOAD(phdr) |
476 | 17.8k | && is_pow2(align) && !((-1+ align) & |
477 | 15.7k | (get_te64(&phdr->p_vaddr) ^ get_te64(&phdr->p_offset))) |
478 | 15.0k | && (addr - get_te64(&phdr->p_vaddr)) < get_te64(&phdr->p_filesz)) { |
479 | 13.1k | return phdr; |
480 | 13.1k | } |
481 | 55.5k | } |
482 | 313 | return nullptr; |
483 | 13.4k | } |
484 | | |
485 | | unsigned |
486 | | PackLinuxElf32::slide_sh_offset(Elf32_Shdr *shdr) |
487 | 0 | { |
488 | 0 | unsigned sh_offset = get_te32(&shdr->sh_offset); |
489 | 0 | unsigned sh_addr = get_te32(&shdr->sh_addr); |
490 | 0 | if (Elf32_Shdr::SHF_WRITE & get_te32(&shdr->sh_flags) |
491 | 0 | || (sh_offset && !sh_addr)) |
492 | 0 | { |
493 | 0 | unsigned newoff = so_slide + sh_offset + (is_asl ? asl_delta : 0); |
494 | 0 | if ((unsigned)this->file_size < newoff) { |
495 | 0 | throwInternalError("bad slide %p %#x", shdr, (unsigned)so_slide); |
496 | 0 | } |
497 | 0 | set_te32(&shdr->sh_offset, newoff); |
498 | 0 | if (sh_addr) // change only if non-zero |
499 | 0 | set_te32(&shdr->sh_addr, |
500 | 0 | so_slide + sh_addr + (is_asl ? asl_delta : 0)); |
501 | 0 | return newoff; |
502 | 0 | } |
503 | 0 | return sh_offset; |
504 | 0 | } |
505 | | |
506 | | void |
507 | | PackLinuxElf32::asl_slide_Shdrs() |
508 | 0 | { |
509 | 0 | Elf32_Shdr *shdr = shdro; |
510 | 0 | for (unsigned j = 0; j < e_shnum; ++shdr, ++j) { |
511 | 0 | unsigned sh_offset = get_te32(&shdr->sh_offset); |
512 | 0 | if (xct_off < sh_offset) { |
513 | 0 | slide_sh_offset(shdr); |
514 | 0 | } |
515 | 0 | } |
516 | 0 | } |
517 | | |
518 | | unsigned |
519 | | PackLinuxElf64::slide_sh_offset(Elf64_Shdr *shdr) |
520 | 0 | { |
521 | 0 | unsigned sh_offset = get_te64(&shdr->sh_offset); |
522 | 0 | unsigned sh_addr = get_te64(&shdr->sh_addr); |
523 | 0 | if (Elf64_Shdr::SHF_WRITE & get_te64(&shdr->sh_flags) |
524 | 0 | || (sh_offset && !sh_addr)) |
525 | 0 | { |
526 | 0 | unsigned newoff = so_slide + sh_offset + (is_asl ? asl_delta : 0); |
527 | 0 | if ((unsigned)this->file_size < newoff) { |
528 | 0 | throwInternalError("bad slide %p %#x", shdr, (unsigned)so_slide); |
529 | 0 | } |
530 | 0 | set_te64(&shdr->sh_offset, newoff); |
531 | 0 | if (sh_addr) // change only if non-zero |
532 | 0 | set_te64(&shdr->sh_addr, |
533 | 0 | so_slide + sh_addr + (is_asl ? asl_delta : 0)); |
534 | 0 | return newoff; |
535 | 0 | } |
536 | 0 | return sh_offset; |
537 | 0 | } |
538 | | |
539 | | void |
540 | | PackLinuxElf64::asl_slide_Shdrs() |
541 | 0 | { |
542 | 0 | Elf64_Shdr *shdr = shdro; |
543 | 0 | for (unsigned j = 0; j < e_shnum; ++shdr, ++j) { |
544 | 0 | unsigned sh_offset = get_te64_32(&shdr->sh_offset); |
545 | 0 | if (xct_off < sh_offset) { |
546 | 0 | slide_sh_offset(shdr); |
547 | 0 | } |
548 | 0 | } |
549 | 0 | } |
550 | | |
551 | | // C_BASE covers the convex hull of the PT_LOAD of the uncompressed module. |
552 | | // It has (PF_W & .p_flags), and is ".bss": empty (0==.p_filesz, except a bug |
553 | | // in Linux kernel forces 0x1000==.p_filesz) with .p_memsz equal to the brk(0). |
554 | | // It is first in order to reserve all // pages, in particular so that if |
555 | | // (64K == .p_align) but at runtime (4K == PAGE_SIZE) then the Linux kernel |
556 | | // does not put [vdso] and [vvar] into alignment holes that the UPX runtime stub |
557 | | // will overwrite. |
558 | | // |
559 | | // Note that C_TEXT[.p_vaddr, +.p_memsz) is a subset of C_BASE. |
560 | | // This requires that the kernel process the ELFxx_Phdr in ascending order, |
561 | | // and does not mind the overlap. The UPX runtime stub will "re-program" |
562 | | // the memory regions anyway. |
563 | | enum { // ordinals in ELFxx_Phdr[] of compressed output |
564 | | C_BASE = 0 // reserve address space |
565 | | , C_TEXT = 1 // compressed data and stub |
566 | | , C_NOTE = 2 // PT_NOTE copied from input |
567 | | , C_GSTK = 3 // PT_GNU_STACK; will be 2 if no PT_NOTE |
568 | | }; |
569 | | |
570 | | off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft) |
571 | 0 | { |
572 | 0 | if (!overlay_offset) { |
573 | 0 | overlay_offset = sizeof(linfo) + (xct_off ? xct_off : sz_elf_hdrs); |
574 | 0 | } |
575 | |
|
576 | 0 | total_out = super::pack3(fo, ft); // loader follows compressed PT_LOADs |
577 | 0 | if (fo && xct_off && !is_asl && Elf32_Dyn::DT_INIT != upx_dt_init) { |
578 | | // Patch user_init_rp. is_asl has done this already in asl_pack2_Shdrs() |
579 | | // Section .init_array[0] must have R_$(ARCH)_RELATIVE relocation. |
580 | 0 | fo->seek((char *)user_init_rp - (char *)&file_image[0], SEEK_SET); |
581 | 0 | Elf32_Rel rel(*(Elf32_Rel const *)user_init_rp); |
582 | 0 | u32_t r_info = get_te32(&((Elf32_Rel const *)user_init_rp)->r_info); |
583 | 0 | u32_t r_type = (Elf32_Ehdr::EM_386 == e_machine) ? R_386_RELATIVE |
584 | 0 | : (Elf32_Ehdr::EM_ARM == e_machine) ? R_ARM_RELATIVE |
585 | 0 | : (Elf32_Ehdr::EM_PPC == e_machine) ? R_PPC_RELATIVE |
586 | 0 | : (Elf32_Ehdr::EM_MIPS == e_machine) ? R_MIPS_32 |
587 | 0 | : 0; |
588 | 0 | set_te32(&rel.r_info, ELF32_R_INFO(ELF32_R_SYM(r_info), r_type)); |
589 | 0 | if (is_asl) { |
590 | 0 | u32_t r_offset = get_te32(&((Elf32_Rel const *)user_init_rp)->r_offset); |
591 | 0 | set_te32(&rel.r_offset, asl_delta + r_offset); |
592 | 0 | } |
593 | 0 | fo->rewrite(&rel, sizeof(rel)); |
594 | 0 | fo->seek(0, SEEK_END); |
595 | | |
596 | | // Value of init_array[0] will be changed later. |
597 | | // See write() of 'cpr_entry' below. |
598 | 0 | } |
599 | | // NOTE: PackLinuxElf::pack3 adjusted xct_off for the extra page |
600 | | |
601 | | // Then compressed gaps (including debuginfo.) |
602 | 0 | for (unsigned k = 0; k < e_phnum; ++k) { |
603 | 0 | Extent x; |
604 | 0 | x.size = find_LOAD_gap(phdri, k, e_phnum); |
605 | 0 | if (x.size) { |
606 | 0 | x.offset = get_te32(&phdri[k].p_offset) + |
607 | 0 | get_te32(&phdri[k].p_filesz); |
608 | 0 | packExtent(x, nullptr, fo); |
609 | 0 | } |
610 | 0 | } |
611 | | // write block end marker (uncompressed size 0) |
612 | 0 | b_info hdr; memset(&hdr, 0, sizeof(hdr)); |
613 | 0 | set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); |
614 | 0 | fo->write(&hdr, sizeof(hdr)); |
615 | 0 | total_out = fpad4(fo, total_out); |
616 | |
|
617 | 0 | if (0==xct_off) { // not shared library |
618 | 0 | set_te32(&elfout.phdr[C_BASE].p_align, 0u - page_mask); |
619 | 0 | elfout.phdr[C_BASE].p_paddr = elfout.phdr[C_BASE].p_vaddr; |
620 | 0 | elfout.phdr[C_BASE].p_offset = 0; |
621 | 0 | unsigned abrk = getbrk(phdri, e_phnum); |
622 | | // vbase handles ET_EXEC. FIXME: pre-linking? |
623 | 0 | unsigned vbase = get_te32(&elfout.phdr[C_BASE].p_vaddr); |
624 | 0 | set_te32(&elfout.phdr[C_BASE].p_filesz, 0x1000); // Linux kernel SIGSEGV if (0==.p_filesz) |
625 | 0 | set_te32(&elfout.phdr[C_BASE].p_memsz, abrk - vbase); |
626 | 0 | set_te32(&elfout.phdr[C_BASE].p_flags, Elf32_Phdr::PF_W|Elf32_Phdr::PF_R); |
627 | 0 | set_te32(&elfout.phdr[C_TEXT].p_filesz, sz_pack2 + lsize); |
628 | 0 | set_te32(&elfout.phdr[C_TEXT].p_memsz, sz_pack2 + lsize); |
629 | 0 | set_te32(&elfout.phdr[C_TEXT].p_vaddr, abrk= (page_mask & (~page_mask + abrk))); |
630 | 0 | elfout.phdr[C_TEXT].p_paddr = elfout.phdr[C_TEXT].p_vaddr; |
631 | 0 | set_te32(&elfout.ehdr.e_entry, abrk + get_te32(&elfout.ehdr.e_entry) - vbase); |
632 | 0 | } |
633 | 0 | if (0!=xct_off) { // shared library |
634 | 0 | unsigned const cpr_entry = load_va + sz_pack2; |
635 | 0 | set_te32(&file_image[user_init_off], cpr_entry); // set the hook |
636 | |
|
637 | 0 | if (user_init_rp) { // decompressor needs hint for DT_INIT_ARRAY |
638 | 0 | Elf32_Dyn *dynp = (Elf32_Dyn *)elf_find_dynptr(Elf32_Dyn::DT_NULL); |
639 | 0 | set_te32(&dynp->d_val, (char *)user_init_rp - (char *)&file_image[0]); |
640 | 0 | } |
641 | |
|
642 | 0 | Elf32_Phdr *const phdr0 = (Elf32_Phdr *)lowmem.subref( |
643 | 0 | "bad e_phoff", e_phoff, e_phnum * sizeof(Elf32_Phdr)); |
644 | 0 | Elf32_Phdr *phdr = phdr0; |
645 | 0 | upx_off_t off = fo->st_size(); // 64 bits |
646 | 0 | so_slide = 0; |
647 | 0 | for (unsigned j = 0; j < e_phnum; ++j, ++phdr) { |
648 | | // p_vaddr and p_paddr do not change! |
649 | 0 | unsigned const len = get_te32(&phdr->p_filesz); |
650 | 0 | unsigned const ioff = get_te32(&phdri[j].p_offset); // without asl_delta |
651 | 0 | unsigned align= get_te32(&phdr->p_align); |
652 | 0 | unsigned const type = get_te32(&phdr->p_type); |
653 | 0 | if (Elf32_Phdr::PT_INTERP==type) { |
654 | | // Rotate to highest position, so it can be lopped |
655 | | // by decrementing e_phnum. |
656 | 0 | memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); // extract |
657 | 0 | memmove(phdr, 1+phdr, (e_phnum - (1+ j))*sizeof(*phdr)); // overlapping |
658 | 0 | memcpy(&phdr[e_phnum - (1+ j)], (unsigned char *)ibuf, sizeof(*phdr)); // to top |
659 | 0 | --phdr; --e_phnum; |
660 | 0 | set_te16(&ehdri.e_phnum, e_phnum); |
661 | 0 | set_te16(&((Elf32_Ehdr *)(unsigned char *)lowmem)->e_phnum, e_phnum); |
662 | 0 | continue; |
663 | 0 | } |
664 | 0 | if (PT_LOAD == type) { |
665 | 0 | if (!ioff) { // first PT_LOAD must contain everything written so far |
666 | 0 | set_te32(&phdr->p_filesz, sz_pack2 + lsize); // is this correct? |
667 | 0 | set_te32(&phdr->p_memsz, sz_pack2 + lsize); |
668 | | // so_entry._start is in 1st PT_LOAD, and must be eXecutable |
669 | 0 | unsigned p_flags = get_te32(&phdr->p_flags); |
670 | 0 | set_te32(&phdr->p_flags, Elf32_Phdr::PF_X | p_flags); |
671 | 0 | } |
672 | 0 | else if ((xct_off - ioff) < len) { // Change length of compressed PT_LOAD. |
673 | 0 | set_te32(&phdr->p_filesz, total_out - ioff); // FIXME (sz_pack2 + lsize - ioff) ? |
674 | 0 | set_te32(&phdr->p_memsz, total_out - ioff); |
675 | 0 | if (user_init_off < xct_off) { // MIPS puts PT_DYNAMIC here |
676 | | // Allow for DT_INIT in a new [stolen] slot |
677 | 0 | unsigned off2 = user_init_off - sizeof(unsigned); |
678 | 0 | fo->seek(off2, SEEK_SET); |
679 | 0 | fo->rewrite(&file_image[off2], 2*sizeof(unsigned)); |
680 | 0 | } |
681 | 0 | } |
682 | 0 | else if (xct_off < ioff) { // Slide subsequent PT_LOAD. |
683 | 0 | if ((1u<<12) < align |
684 | 0 | && ( Elf32_Ehdr::EM_386 == e_machine |
685 | 0 | || Elf32_Ehdr::EM_ARM == e_machine) // FIXME: other $ARCH ? |
686 | 0 | ) { |
687 | 0 | align = 1u<<12; |
688 | 0 | set_te32(&phdr->p_align, align); |
689 | 0 | } |
690 | 0 | off = fpadN(fo, (-1 + align) & (ioff - off)); |
691 | 0 | if (!so_slide) { // only once |
692 | 0 | so_slide = off - ((is_asl ? asl_delta : 0) + ioff); |
693 | | //fprintf(stderr, "\nso_slide = %#x\n", (unsigned)so_slide); |
694 | | //asl_slide_Shdrs(); |
695 | 0 | } |
696 | 0 | set_te32(&phdr->p_offset, off); |
697 | 0 | fo->seek(off, SEEK_SET); |
698 | 0 | fo->write(&file_image[ioff], len); |
699 | 0 | off += len; |
700 | 0 | total_out = off; |
701 | |
|
702 | 0 | if ((user_init_off - ioff) < len) { |
703 | 0 | fo->seek(user_init_off + so_slide, SEEK_SET); |
704 | 0 | unsigned word = cpr_entry; |
705 | 0 | set_te32(&word, cpr_entry); |
706 | 0 | fo->rewrite(&word, sizeof(word)); |
707 | 0 | fo->seek(0, SEEK_END); |
708 | 0 | } |
709 | 0 | } |
710 | 0 | continue; // all done with this PT_LOAD |
711 | 0 | } |
712 | 0 | if (xct_off < ioff) { |
713 | 0 | set_te32(&phdr->p_offset, so_slide + (is_asl ? asl_delta : 0) + ioff); |
714 | 0 | } |
715 | 0 | } // end each Phdr |
716 | |
|
717 | 0 | if (sec_arm_attr || is_asl) { // must update Shdr.sh_offset for so_slide |
718 | 0 | Elf32_Shdr *shdr = shdri; |
719 | 0 | for (unsigned j = 0; j < e_shnum; ++shdr, ++j) { |
720 | 0 | unsigned sh_type = get_te32(&shdr->sh_type); |
721 | 0 | if (Elf32_Shdr::SHT_REL == sh_type |
722 | 0 | && n_jmp_slot // FIXME who sets this? |
723 | 0 | && !strcmp(".rel.plt", get_te32(&shdr->sh_name) + shstrtab)) { |
724 | 0 | unsigned va = elf_unsigned_dynamic(Elf32_Dyn::DT_PLTGOT) |
725 | 0 | - (is_asl ? asl_delta : 0); |
726 | | // Now use the old Phdrs (phdri) |
727 | 0 | Elf32_Phdr const *phva; |
728 | 0 | phva = elf_find_Phdr_for_va(va, phdri, e_phnum); |
729 | 0 | unsigned old_off = (va - get_te32(&phva->p_vaddr)) |
730 | 0 | + get_te32(&phva->p_offset); |
731 | | |
732 | | // Now use the new Phdrs (phdr0) |
733 | 0 | va += (is_asl ? asl_delta : 0); |
734 | 0 | phva = elf_find_Phdr_for_va(va, phdr0, e_phnum); |
735 | 0 | unsigned new_off = (va - get_te32(&phva->p_vaddr)) |
736 | 0 | + get_te32(&phva->p_offset); |
737 | |
|
738 | 0 | if (fo && n_jmp_slot) { |
739 | 0 | fo->seek(new_off, SEEK_SET); |
740 | 0 | fo->rewrite(&file_image[old_off], n_jmp_slot * 4); |
741 | 0 | } |
742 | 0 | } |
743 | 0 | if (j && shdr->sh_addr == 0 |
744 | 0 | && get_te32(&shdr->sh_offset) < xct_off) { |
745 | | // Try to be nice by sliding; but still fails if compressed. |
746 | | // So don't do it unless appending plain text of shstrtab. |
747 | 0 | unsigned sh_off = get_te32(&shdr->sh_offset); |
748 | 0 | if (xct_off < sh_off) { |
749 | 0 | slide_sh_offset(shdr); |
750 | 0 | } |
751 | 0 | } |
752 | 0 | } |
753 | | // Maybe: append plain text of shstrtab strings? |
754 | 0 | fo->seek(total_out, SEEK_SET); |
755 | 0 | if (xct_off < e_shoff) { |
756 | 0 | set_te32(&((Elf32_Ehdr *)lowmem.getVoidPtr())->e_shoff, total_out); |
757 | 0 | if (fo) { |
758 | 0 | fo->write(shdri, e_shnum * sizeof(*shdr)); |
759 | 0 | total_out += e_shnum * sizeof(*shdr); |
760 | 0 | } |
761 | 0 | } |
762 | 0 | } |
763 | 0 | else { // output has no Shdr |
764 | 0 | ehdri.e_shnum = 0; |
765 | 0 | ehdri.e_shoff = 0; |
766 | 0 | ehdri.e_shstrndx = 0; |
767 | 0 | } |
768 | 0 | } |
769 | 0 | return total_out; |
770 | 0 | } |
771 | | |
772 | | off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft) |
773 | 0 | { |
774 | 0 | if (!overlay_offset) { |
775 | 0 | overlay_offset = sizeof(linfo) + (xct_off ? xct_off : sz_elf_hdrs); |
776 | 0 | } |
777 | |
|
778 | 0 | total_out = super::pack3(fo, ft); // loader follows compressed PT_LOADs |
779 | 0 | if (fo && xct_off && Elf64_Dyn::DT_INIT != upx_dt_init) { // patch user_init_rp |
780 | 0 | fo->seek((char *)user_init_rp - (char *)&file_image[0], SEEK_SET); |
781 | 0 | Elf64_Rela rela(*(Elf64_Rela const *)user_init_rp); |
782 | | //u64_t r_info = get_te64(&((Elf64_Rela const *)user_init_rp)->r_info); |
783 | 0 | u32_t r_type = (Elf64_Ehdr::EM_AARCH64 == e_machine) ? R_AARCH64_RELATIVE |
784 | 0 | : (Elf64_Ehdr::EM_X86_64 == e_machine) ? R_X86_64_RELATIVE |
785 | 0 | : (Elf64_Ehdr::EM_PPC64 == e_machine) ? R_PPC64_RELATIVE |
786 | 0 | : 0; |
787 | 0 | set_te64(&rela.r_info, ELF64_R_INFO(0 /*ELF64_R_SYM(r_info)*/, r_type)); |
788 | 0 | set_te64(&rela.r_addend, sz_pack2); // entry to decompressor |
789 | 0 | fo->rewrite(&rela, sizeof(rela)); |
790 | |
|
791 | 0 | fo->seek(0, SEEK_END); |
792 | 0 | } |
793 | | // NOTE: PackLinuxElf::pack3 adjusted xct_off for the extra page |
794 | | |
795 | | // Then compressed gaps (including debuginfo.) |
796 | 0 | for (unsigned k = 0; k < e_phnum; ++k) { |
797 | 0 | Extent x; |
798 | 0 | x.size = find_LOAD_gap(phdri, k, e_phnum); |
799 | 0 | if (x.size) { |
800 | 0 | x.offset = get_te64(&phdri[k].p_offset) + |
801 | 0 | get_te64(&phdri[k].p_filesz); |
802 | 0 | packExtent(x, nullptr, fo); |
803 | 0 | } |
804 | 0 | } |
805 | | // write block end marker (uncompressed size 0) |
806 | 0 | b_info hdr; memset(&hdr, 0, sizeof(hdr)); |
807 | 0 | set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); |
808 | 0 | fo->write(&hdr, sizeof(hdr)); |
809 | 0 | total_out = fpad4(fo, total_out); |
810 | |
|
811 | 0 | if (0==xct_off) { // not shared library |
812 | 0 | set_te64(&elfout.phdr[C_BASE].p_align, ((u64_t)0) - page_mask); |
813 | 0 | elfout.phdr[C_BASE].p_paddr = elfout.phdr[C_BASE].p_vaddr; |
814 | 0 | elfout.phdr[C_BASE].p_offset = 0; |
815 | 0 | u64_t abrk = getbrk(phdri, e_phnum); |
816 | | // vbase handles ET_EXEC. FIXME: pre-linking? |
817 | 0 | u64_t const vbase = get_te64(&elfout.phdr[C_BASE].p_vaddr); |
818 | 0 | set_te64(&elfout.phdr[C_BASE].p_filesz, 0x1000); // Linux kernel SIGSEGV if (0==.p_filesz) |
819 | 0 | set_te64(&elfout.phdr[C_BASE].p_memsz, abrk - vbase); |
820 | 0 | set_te32(&elfout.phdr[C_BASE].p_flags, Elf64_Phdr::PF_W|Elf64_Phdr::PF_R); |
821 | 0 | set_te64(&elfout.phdr[C_TEXT].p_filesz, sz_pack2 + lsize); |
822 | 0 | set_te64(&elfout.phdr[C_TEXT].p_memsz, sz_pack2 + lsize); |
823 | 0 | set_te64(&elfout.phdr[C_TEXT].p_vaddr, abrk= (page_mask & (~page_mask + abrk))); |
824 | 0 | elfout.phdr[C_TEXT].p_paddr = elfout.phdr[C_TEXT].p_vaddr; |
825 | 0 | set_te64(&elfout.ehdr.e_entry, abrk + get_te64(&elfout.ehdr.e_entry) - vbase); |
826 | 0 | } |
827 | 0 | if (0!=xct_off) { // shared library |
828 | 0 | u64_t const cpr_entry = load_va + sz_pack2; |
829 | 0 | set_te64(&file_image[user_init_off], cpr_entry); // set the hook |
830 | |
|
831 | 0 | if (user_init_rp) { // decompressor needs hint for DT_INIT_ARRAY |
832 | 0 | Elf64_Dyn *dynp = (Elf64_Dyn *)elf_find_dynptr(Elf64_Dyn::DT_NULL); |
833 | 0 | set_te64(&dynp->d_val, (char *)user_init_rp - (char *)&file_image[0]); |
834 | 0 | } |
835 | |
|
836 | 0 | Elf64_Phdr *const phdr0 = (Elf64_Phdr *)lowmem.subref( |
837 | 0 | "bad e_phoff", e_phoff, e_phnum * sizeof(Elf64_Phdr)); |
838 | 0 | Elf64_Phdr *phdr = phdr0; |
839 | 0 | upx_off_t off = fo->st_size(); // 64 bits |
840 | 0 | so_slide = 0; |
841 | 0 | for (unsigned j = 0; j < e_phnum; ++j, ++phdr) { |
842 | | // p_vaddr and p_paddr do not change! |
843 | 0 | u64_t const len = get_te64(&phdr->p_filesz); |
844 | 0 | u64_t const ioff = get_te64(&phdri[j].p_offset); // without asl_delta |
845 | 0 | u64_t align= get_te64(&phdr->p_align); |
846 | 0 | unsigned const type = get_te32(&phdr->p_type); |
847 | 0 | if (Elf64_Phdr::PT_INTERP==type) { |
848 | | // Rotate to highest position, so it can be lopped |
849 | | // by decrementing e_phnum. |
850 | 0 | memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); // extract |
851 | 0 | memmove(phdr, 1+phdr, (e_phnum - (1+ j))*sizeof(*phdr)); // overlapping |
852 | 0 | memcpy(&phdr[e_phnum - (1+ j)], (unsigned char *)ibuf, sizeof(*phdr)); // to top |
853 | 0 | --phdr; --e_phnum; |
854 | 0 | set_te16(&ehdri.e_phnum, e_phnum); |
855 | 0 | set_te16(&((Elf64_Ehdr *)(unsigned char *)lowmem)->e_phnum, e_phnum); |
856 | 0 | continue; |
857 | 0 | } |
858 | 0 | if (PT_LOAD == type) { |
859 | 0 | if (!ioff) { // first PT_LOAD must contain everything written so far |
860 | 0 | set_te64(&phdr->p_filesz, sz_pack2 + lsize); // is this correct? |
861 | 0 | set_te64(&phdr->p_memsz, sz_pack2 + lsize); |
862 | 0 | } |
863 | 0 | else if ((xct_off - ioff) < len) { // Change length of compressed PT_LOAD. |
864 | 0 | set_te64(&phdr->p_filesz, total_out - ioff); // FIXME (sz_pack2 + lsize - ioff) ? |
865 | 0 | set_te64(&phdr->p_memsz, total_out - ioff); |
866 | 0 | if (user_init_off < xct_off) { // MIPS puts PT_DYNAMIC here |
867 | | // Allow for DT_INIT in a new [stolen] slot |
868 | 0 | unsigned off2 = user_init_off - sizeof(u64_t); |
869 | 0 | fo->seek(off2, SEEK_SET); |
870 | 0 | fo->rewrite(&file_image[off2], 2*sizeof(u64_t)); |
871 | 0 | } |
872 | 0 | } |
873 | 0 | else if (xct_off < ioff) { // Slide subsequent PT_LOAD. |
874 | 0 | if ((1u<<12) < align |
875 | 0 | && Elf64_Ehdr::EM_X86_64 == e_machine // FIXME: other $ARCH ? |
876 | 0 | ) { |
877 | 0 | align = 1u<<12; |
878 | 0 | set_te64(&phdr->p_align, align); |
879 | 0 | } |
880 | 0 | off = fpadN(fo, (-1 + align) & (ioff - off)); |
881 | 0 | if (!so_slide) { // only once |
882 | 0 | so_slide = off - ((is_asl ? asl_delta : 0) + ioff); |
883 | | //fprintf(stderr, "\nso_slide = %#x\n", (unsigned)so_slide); |
884 | | //asl_slide_Shdrs(); |
885 | 0 | } |
886 | 0 | set_te64(&phdr->p_offset, off); |
887 | 0 | fo->seek(off, SEEK_SET); |
888 | 0 | fo->write(&file_image[ioff], len); |
889 | 0 | off += len; |
890 | 0 | total_out = off; |
891 | |
|
892 | 0 | if ((user_init_off - ioff) < len) { |
893 | 0 | fo->seek(user_init_off + so_slide, SEEK_SET); |
894 | 0 | u64_t word = cpr_entry; |
895 | 0 | set_te64(&word, cpr_entry); |
896 | 0 | fo->rewrite(&word, sizeof(word)); |
897 | 0 | fo->seek(0, SEEK_END); |
898 | 0 | } |
899 | 0 | } |
900 | 0 | continue; // all done with this PT_LOAD |
901 | 0 | } |
902 | 0 | if (xct_off < ioff) { |
903 | 0 | set_te64(&phdr->p_offset, so_slide + (is_asl ? asl_delta : 0) + ioff); |
904 | 0 | } |
905 | 0 | } // end each Phdr |
906 | |
|
907 | 0 | if (sec_arm_attr || is_asl) { // must update Shdr.sh_offset for so_slide |
908 | | // Update {DYNAMIC}.sh_offset by so_slide. |
909 | 0 | Elf64_Shdr *shdr = (Elf64_Shdr *)lowmem.subref( // FIXME: use shdri ? |
910 | 0 | "bad e_shoff", xct_off - (is_asl ? asl_delta : 0), e_shnum * sizeof(Elf64_Shdr)); |
911 | 0 | for (unsigned j = 0; j < e_shnum; ++shdr, ++j) { |
912 | 0 | unsigned sh_type = get_te32(&shdr->sh_type); |
913 | 0 | unsigned sh_flags = get_te64(&shdr->sh_flags); // all SHF_ are 32-bit anyway |
914 | 0 | unsigned sh_offset = get_te64(&shdr->sh_offset); // already asl_delta |
915 | 0 | if (Elf64_Shdr::SHF_ALLOC & sh_flags |
916 | 0 | && Elf64_Shdr::SHF_WRITE & sh_flags |
917 | 0 | && xct_off < sh_offset) { |
918 | 0 | set_te64(&shdr->sh_offset, so_slide + sh_offset); |
919 | 0 | } |
920 | 0 | if (Elf64_Shdr::SHT_RELA == sh_type |
921 | 0 | && n_jmp_slot // FIXME: does this apply to SHT_RELA ? |
922 | 0 | && !strcmp(".rel.plt", get_te32(&shdr->sh_name) + shstrtab)) { |
923 | 0 | u64_t va = elf_unsigned_dynamic(Elf64_Dyn::DT_PLTGOT) - (is_asl ? asl_delta : 0); |
924 | | // Now use the old Phdrs (phdri) |
925 | 0 | Elf64_Phdr const *phva; |
926 | 0 | phva = elf_find_Phdr_for_va(va, phdri, e_phnum); |
927 | 0 | u64_t old_off = (va - get_te64(&phva->p_vaddr)) |
928 | 0 | + get_te64(&phva->p_offset); |
929 | | |
930 | | // Now use the new Phdrs (phdr0) |
931 | 0 | va += (is_asl ? asl_delta : 0); |
932 | 0 | phva = elf_find_Phdr_for_va(va, phdr0, e_phnum); |
933 | 0 | u64_t new_off = (va - get_te64(&phva->p_vaddr)) |
934 | 0 | + get_te64(&phva->p_offset); |
935 | |
|
936 | 0 | if (fo && n_jmp_slot) { |
937 | 0 | fo->seek(new_off, SEEK_SET); |
938 | 0 | fo->rewrite(&file_image[old_off], n_jmp_slot * 8); |
939 | 0 | } |
940 | 0 | } |
941 | 0 | if (j && shdr->sh_addr == 0 |
942 | 0 | && get_te64_32(&shdr->sh_offset) < xct_off) { // UPX_RSIZE_MAX_MEM protects us |
943 | | // Try to be nice by sliding; but still fails if compressed. |
944 | | // So don't do it unless appending plain text of shstrtab. |
945 | 0 | unsigned sh_off = get_te64_32(&shdr->sh_offset); // UPX_RSIZE_MAX_MEM protects us |
946 | 0 | if (xct_off < sh_off) { |
947 | 0 | set_te64(&shdr->sh_offset, sh_off + so_slide); |
948 | 0 | } |
949 | 0 | } |
950 | 0 | } |
951 | | // Maybe: append plain text of shstrtab strings? |
952 | 0 | fo->seek(total_out, SEEK_SET); |
953 | 0 | if (xct_off < e_shoff) { |
954 | 0 | set_te32(&((Elf32_Ehdr *)lowmem.getVoidPtr())->e_shoff, total_out); |
955 | 0 | if (fo) { |
956 | 0 | fo->write(shdri, e_shnum * sizeof(*shdr)); |
957 | 0 | total_out += e_shnum * sizeof(*shdr); |
958 | 0 | } |
959 | 0 | } |
960 | 0 | } |
961 | 0 | else { // output has no Shdr |
962 | 0 | ehdri.e_shnum = 0; |
963 | 0 | ehdri.e_shoff = 0; |
964 | 0 | ehdri.e_shstrndx = 0; |
965 | 0 | } |
966 | 0 | } |
967 | 0 | return total_out; |
968 | 0 | } |
969 | | |
970 | | void |
971 | | PackLinuxElf::addStubEntrySections(Filter const *, unsigned m_decompr) |
972 | 0 | { |
973 | 0 | (void)m_decompr; // FIXME |
974 | 0 | if (hasLoaderSection("ELFMAINX")) { |
975 | 0 | addLoader("ELFMAINX", nullptr); |
976 | 0 | } |
977 | 0 | if (hasLoaderSection("ELFMAINXu")) { |
978 | | // brk() trouble if static |
979 | 0 | addLoader("ELFMAINXu", nullptr); |
980 | 0 | } |
981 | 0 | addLoader( |
982 | 0 | ( M_IS_NRV2E(ph_forced_method(ph.method)) ? "NRV_HEAD,NRV2E,NRV_TAIL" |
983 | 0 | : M_IS_NRV2D(ph_forced_method(ph.method)) ? "NRV_HEAD,NRV2D,NRV_TAIL" |
984 | 0 | : M_IS_NRV2B(ph_forced_method(ph.method)) ? "NRV_HEAD,NRV2B,NRV_TAIL" |
985 | 0 | : M_IS_LZMA(ph_forced_method(ph.method)) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30" |
986 | 0 | : nullptr), nullptr); |
987 | 0 | if (hasLoaderSection("CFLUSH")) |
988 | 0 | addLoader("CFLUSH"); |
989 | 0 | addLoader("ELFMAINY,IDENTSTR", nullptr); |
990 | 0 | if (hasLoaderSection("ELFMAINZe")) { // ppc64 big-endian only |
991 | 0 | addLoader("ELFMAINZe", nullptr); |
992 | 0 | } |
993 | 0 | addLoader("+40,ELFMAINZ", nullptr); |
994 | 0 | if (hasLoaderSection("ANDMAJNZ")) { // Android trouble with args to DT_INIT |
995 | 0 | if (is_asl) { |
996 | 0 | addLoader("ANDMAJNZ", nullptr); // constant PAGE_SIZE |
997 | 0 | } |
998 | 0 | else { |
999 | 0 | addLoader("ELFMAJNZ", nullptr); // PAGE_SIZE from AT_PAGESZ |
1000 | 0 | } |
1001 | 0 | addLoader("ELFMAKNZ", nullptr); |
1002 | 0 | } |
1003 | 0 | if (hasLoaderSection("ELFMAINZu")) { |
1004 | 0 | addLoader("ELFMAINZu", nullptr); |
1005 | 0 | } |
1006 | 0 | addLoader("FOLDEXEC", nullptr); |
1007 | 0 | } |
1008 | | |
1009 | | |
1010 | | void PackLinuxElf::defineSymbols(Filter const *) |
1011 | 0 | { |
1012 | 0 | linker->defineSymbol("O_BINFO", o_binfo |
1013 | 0 | | ((!!opt->o_unix.is_ptinterp) << 0) |
1014 | 0 | | ((!!opt->o_unix.unmap_all_pages) << 1) ); |
1015 | 0 | } |
1016 | | |
1017 | | void PackLinuxElf32::defineSymbols(Filter const *ft) |
1018 | 0 | { |
1019 | 0 | PackLinuxElf::defineSymbols(ft); |
1020 | 0 | } |
1021 | | |
1022 | | void PackLinuxElf64::defineSymbols(Filter const *ft) |
1023 | 0 | { |
1024 | 0 | PackLinuxElf::defineSymbols(ft); |
1025 | 0 | } |
1026 | | |
1027 | | PackLinuxElf32::PackLinuxElf32(InputFile *f) |
1028 | 172k | : super(f), phdri(nullptr), shdri(nullptr), |
1029 | 172k | n_phdrx(0), sz_phdrx(0), |
1030 | 172k | page_mask(~0u<<lg2_page), |
1031 | 172k | dynseg(nullptr), hashtab(nullptr), hashend(nullptr), |
1032 | 172k | gashtab(nullptr), gashend(nullptr), dynsym(nullptr), |
1033 | 172k | jni_onload_sym(nullptr), |
1034 | 172k | sec_strndx(nullptr), sec_dynsym(nullptr), sec_dynstr(nullptr) |
1035 | 172k | , sec_arm_attr(nullptr) |
1036 | 172k | { |
1037 | 172k | memset(&ehdri, 0, sizeof(ehdri)); |
1038 | 172k | n_jmp_slot = 0; |
1039 | 172k | if (f) { |
1040 | 172k | f->seek(0, SEEK_SET); |
1041 | 172k | f->readx(&ehdri, sizeof(ehdri)); |
1042 | 172k | } |
1043 | 172k | } |
1044 | | |
1045 | | PackLinuxElf32::~PackLinuxElf32() |
1046 | | { |
1047 | | } |
1048 | | |
1049 | | void PackLinuxElf32::add_phdrx(Elf32_Phdr const *phdr) |
1050 | 0 | { |
1051 | 0 | if (END_PHDRX <= n_phdrx) { |
1052 | 0 | throwCantPack("too many Phdr %u", (unsigned)(phdr - phdri)); |
1053 | 0 | } |
1054 | 0 | phdrx[n_phdrx++] = phdr; |
1055 | 0 | } |
1056 | | |
1057 | | PackLinuxElf64::PackLinuxElf64(InputFile *f) |
1058 | 69.1k | : super(f), phdri(nullptr), shdri(nullptr), |
1059 | 69.1k | n_phdrx(0), sz_phdrx(0), |
1060 | 69.1k | page_mask(~0ull<<lg2_page), |
1061 | 69.1k | dynseg(nullptr), hashtab(nullptr), hashend(nullptr), |
1062 | 69.1k | gashtab(nullptr), gashend(nullptr), dynsym(nullptr), |
1063 | 69.1k | jni_onload_sym(nullptr), |
1064 | 69.1k | sec_strndx(nullptr), sec_dynsym(nullptr), sec_dynstr(nullptr) |
1065 | 69.1k | , sec_arm_attr(nullptr) |
1066 | 69.1k | { |
1067 | 69.1k | memset(&ehdri, 0, sizeof(ehdri)); |
1068 | 69.1k | n_jmp_slot = 0; |
1069 | 69.1k | if (f) { |
1070 | 69.1k | f->seek(0, SEEK_SET); |
1071 | 69.1k | f->readx(&ehdri, sizeof(ehdri)); |
1072 | 69.1k | } |
1073 | 69.1k | } |
1074 | | |
1075 | | PackLinuxElf64::~PackLinuxElf64() |
1076 | | { |
1077 | | } |
1078 | | |
1079 | | void PackLinuxElf64::add_phdrx(Elf64_Phdr const *phdr) |
1080 | 0 | { |
1081 | 0 | if (END_PHDRX <= n_phdrx) { |
1082 | 0 | throwCantPack("too many Phdr %u", (unsigned)(phdr - phdri)); |
1083 | 0 | } |
1084 | 0 | phdrx[n_phdrx++] = phdr; |
1085 | 0 | } |
1086 | | |
1087 | | // FIXME: should be templated with PackLinuxElf32help1 |
1088 | | void |
1089 | | PackLinuxElf64::PackLinuxElf64help1(InputFile *f) |
1090 | 69.4k | { |
1091 | 69.4k | e_type = get_te16(&ehdri.e_type); |
1092 | 69.4k | e_phnum = get_te16(&ehdri.e_phnum); |
1093 | 69.4k | e_shnum = get_te16(&ehdri.e_shnum); |
1094 | 69.4k | unsigned const e_phentsize = get_te16(&ehdri.e_phentsize); |
1095 | 69.4k | if (memcmp((char const *)&ehdri, "\x7f\x45\x4c\x46", 4) // "\177ELF" |
1096 | 32.2k | || ehdri.e_ident[Elf64_Ehdr::EI_CLASS]!=Elf64_Ehdr::ELFCLASS64 |
1097 | 17.6k | || sizeof(Elf64_Phdr) != e_phentsize |
1098 | 7.97k | || (Elf64_Ehdr::ELFDATA2MSB == ehdri.e_ident[Elf64_Ehdr::EI_DATA] |
1099 | 1.96k | && &N_BELE_RTP::be_policy != bele) |
1100 | 7.95k | || (Elf64_Ehdr::ELFDATA2LSB == ehdri.e_ident[Elf64_Ehdr::EI_DATA] |
1101 | 61.4k | && &N_BELE_RTP::le_policy != bele)) { |
1102 | 61.4k | e_phoff = 0; |
1103 | 61.4k | e_shoff = 0; |
1104 | 61.4k | sz_phdrs = 0; |
1105 | 61.4k | return; |
1106 | 61.4k | } |
1107 | 7.94k | if (0==e_phnum) throwCantUnpack("0==e_phnum"); |
1108 | 7.94k | e_phoff = get_te64(&ehdri.e_phoff); |
1109 | 7.94k | upx_uint64_t const last_Phdr = e_phoff + e_phnum * sizeof(Elf64_Phdr); |
1110 | 7.94k | if (last_Phdr < e_phoff // wrap-around |
1111 | 7.91k | || e_phoff != sizeof(Elf64_Ehdr) // must be contiguous |
1112 | 7.61k | || (unsigned long)file_size < last_Phdr) { |
1113 | 347 | throwCantUnpack("bad e_phoff %p", (void *)e_phoff); |
1114 | 347 | } |
1115 | 7.59k | e_shoff = get_te64(&ehdri.e_shoff); |
1116 | 7.59k | upx_uint64_t const last_Shdr = e_shoff + e_shnum * sizeof(Elf64_Shdr); |
1117 | 7.59k | if (last_Shdr < e_shoff // wrap-around |
1118 | 7.38k | || (e_shnum && e_shoff < last_Phdr) |
1119 | 7.08k | || (unsigned long)file_size < last_Shdr) { |
1120 | 5.99k | if (opt->cmd == CMD_COMPRESS) { |
1121 | 0 | throwCantUnpack("bad e_shoff %p", (void *)e_shoff); |
1122 | 0 | } |
1123 | 5.99k | } |
1124 | 7.59k | sz_phdrs = e_phnum * e_phentsize; |
1125 | 7.59k | sz_elf_hdrs = sz_phdrs + sizeof(Elf64_Ehdr) + |
1126 | 7.59k | n_phdrx * sizeof(Elf32_Phdr); // phdrx bodies later: ::generateElfHdr |
1127 | | |
1128 | 7.59k | if (f && Elf64_Ehdr::ET_DYN!=e_type) { |
1129 | 2.33k | unsigned const len = file_size; // (sz_phdrs + e_phoff) except --preserve-build-id |
1130 | 2.33k | alloc_file_image(file_image, len); |
1131 | 2.33k | f->seek(0, SEEK_SET); |
1132 | 2.33k | f->readx(file_image, len); |
1133 | 2.33k | phdri= (Elf64_Phdr *)(e_phoff + file_image); // do not free() !! |
1134 | 2.33k | } |
1135 | 7.59k | if (f && Elf64_Ehdr::ET_DYN==e_type) { |
1136 | | // The DT_SYMTAB has no designated length. Read the whole file. |
1137 | 5.26k | alloc_file_image(file_image, file_size); |
1138 | 5.26k | f->seek(0, SEEK_SET); |
1139 | 5.26k | f->readx(file_image, file_size); |
1140 | 5.26k | phdri= (file_size <= (unsigned)e_phoff) ? nullptr : (Elf64_Phdr *)(e_phoff + file_image); // do not free() !! |
1141 | 5.26k | if (!(opt->cmd == CMD_COMPRESS && e_shoff < (upx_uint64_t)file_size && mb_shdr.getSize() == 0)) { |
1142 | 5.26k | shdri = nullptr; |
1143 | 5.26k | } |
1144 | 0 | else if (e_shnum && e_shoff && ehdri.e_shentsize) { |
1145 | 0 | fi->seek(e_shoff, SEEK_SET); |
1146 | 0 | mb_shdr.alloc( sizeof(Elf64_Shdr) * e_shnum); |
1147 | 0 | shdri = (Elf64_Shdr *)mb_shdr.getVoidPtr(); |
1148 | 0 | fi->readx(shdri, sizeof(Elf64_Shdr) * e_shnum); |
1149 | 0 | } |
1150 | 0 | else { |
1151 | 0 | shdri = nullptr; |
1152 | 0 | } |
1153 | 5.26k | sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM); |
1154 | 5.26k | if (sec_dynsym) { |
1155 | 0 | unsigned t = get_te32(&sec_dynsym->sh_link); |
1156 | 0 | if (e_shnum <= t) |
1157 | 0 | throwCantPack("bad dynsym->sh_link"); |
1158 | 0 | sec_dynstr = &shdri[t]; |
1159 | 0 | } |
1160 | | |
1161 | 5.26k | Elf64_Phdr const *phdr= phdri; |
1162 | 37.7k | for (int j = e_phnum; --j>=0; ++phdr) |
1163 | 32.4k | if (Elf64_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { |
1164 | 4.17k | upx_uint64_t offset = check_pt_dynamic(phdr); |
1165 | 4.17k | dynseg= (Elf64_Dyn *)(offset + file_image); |
1166 | 4.17k | invert_pt_dynamic(dynseg, |
1167 | 4.17k | umin(get_te64(&phdr->p_filesz), file_size_u - offset)); |
1168 | 4.17k | } |
1169 | 28.2k | else if (is_LOAD(phdr)) { |
1170 | 4.85k | check_pt_load(phdr); |
1171 | 4.85k | } |
1172 | | // elf_find_dynamic() returns 0 if 0==dynseg. |
1173 | 5.26k | dynstr = (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB); |
1174 | 5.26k | dynsym = (Elf64_Sym /*const*/ *)elf_find_dynamic(Elf64_Dyn::DT_SYMTAB); |
1175 | 5.26k | gashtab = (unsigned const *)elf_find_dynamic(Elf64_Dyn::DT_GNU_HASH); |
1176 | 5.26k | hashtab = (unsigned const *)elf_find_dynamic(Elf64_Dyn::DT_HASH); |
1177 | 5.26k | if (3& ((upx_uintptr_t)dynsym | (upx_uintptr_t)gashtab | (upx_uintptr_t)hashtab)) { |
1178 | 16 | throwCantPack("unaligned DT_SYMTAB, DT_GNU_HASH, or DT_HASH/n"); |
1179 | 16 | } |
1180 | 5.25k | jni_onload_sym = elf_lookup("JNI_OnLoad"); |
1181 | 5.25k | if (jni_onload_sym) { |
1182 | 10 | jni_onload_va = get_te64(&jni_onload_sym->st_value); |
1183 | 10 | jni_onload_va = 0; // FIXME not understood; need example |
1184 | 10 | } |
1185 | 5.25k | } |
1186 | 7.59k | } |
1187 | | |
1188 | | Linker* PackLinuxElf64amd::newLinker() const |
1189 | 0 | { |
1190 | 0 | return new ElfLinkerAMD64; |
1191 | 0 | } |
1192 | | |
1193 | | Linker* PackLinuxElf64arm::newLinker() const |
1194 | 0 | { |
1195 | 0 | return new ElfLinkerArm64LE; |
1196 | 0 | } |
1197 | | |
1198 | | int const * |
1199 | | PackLinuxElf::getCompressionMethods(int method, int level) const |
1200 | 0 | { |
1201 | | // No real dependency on LE32. |
1202 | 0 | return Packer::getDefaultCompressionMethods_le32(method, level); |
1203 | 0 | } |
1204 | | |
1205 | | int const * |
1206 | | PackLinuxElf32armLe::getCompressionMethods(int method, int level) const |
1207 | 0 | { |
1208 | 0 | return Packer::getDefaultCompressionMethods_8(method, level); |
1209 | 0 | } |
1210 | | |
1211 | | int const * |
1212 | | PackLinuxElf32armBe::getCompressionMethods(int method, int level) const |
1213 | 0 | { |
1214 | 0 | return Packer::getDefaultCompressionMethods_8(method, level); |
1215 | 0 | } |
1216 | | |
1217 | | int const * |
1218 | | PackLinuxElf32ppc::getFilters() const |
1219 | 0 | { |
1220 | 0 | static const int filters[] = { |
1221 | 0 | 0xd0, |
1222 | 0 | FT_END }; |
1223 | 0 | return filters; |
1224 | 0 | } |
1225 | | |
1226 | | int const * |
1227 | | PackLinuxElf64ppcle::getFilters() const |
1228 | 0 | { |
1229 | 0 | static const int filters[] = { |
1230 | 0 | 0xd0, |
1231 | 0 | FT_END }; |
1232 | 0 | return filters; |
1233 | 0 | } |
1234 | | |
1235 | | int const * |
1236 | | PackLinuxElf64ppc::getFilters() const |
1237 | 0 | { |
1238 | 0 | static const int filters[] = { |
1239 | 0 | 0xd0, |
1240 | 0 | FT_END }; |
1241 | 0 | return filters; |
1242 | 0 | } |
1243 | | |
1244 | | int const * |
1245 | | PackLinuxElf64amd::getFilters() const |
1246 | 0 | { |
1247 | 0 | static const int filters[] = { |
1248 | 0 | 0x49, |
1249 | 0 | FT_END }; |
1250 | 0 | return filters; |
1251 | 0 | } |
1252 | | |
1253 | | int const * |
1254 | | PackLinuxElf64arm::getFilters() const |
1255 | 0 | { |
1256 | 0 | static const int filters[] = { |
1257 | 0 | 0x52, |
1258 | 0 | FT_END }; |
1259 | 0 | return filters; |
1260 | 0 | } |
1261 | | |
1262 | | void PackLinuxElf32::patchLoader() |
1263 | 0 | { |
1264 | 0 | } |
1265 | | |
1266 | | void PackLinuxElf64::patchLoader() |
1267 | 0 | { |
1268 | 0 | } |
1269 | | |
1270 | | void PackLinuxElf32::ARM_updateLoader(OutputFile * /*fo*/) |
1271 | 0 | { |
1272 | 0 | set_te32(&elfout.ehdr.e_entry, sz_pack2 + |
1273 | 0 | linker->getSymbolOffset("_start") + |
1274 | 0 | get_te32(&elfout.phdr[C_TEXT].p_vaddr)); |
1275 | 0 | } |
1276 | | |
1277 | | void PackLinuxElf32armLe::updateLoader(OutputFile *fo) |
1278 | 0 | { |
1279 | 0 | ARM_updateLoader(fo); |
1280 | 0 | } |
1281 | | |
1282 | | void PackLinuxElf32armBe::updateLoader(OutputFile *fo) |
1283 | 0 | { |
1284 | 0 | ARM_updateLoader(fo); |
1285 | 0 | } |
1286 | | |
1287 | | void PackLinuxElf32mipsel::updateLoader(OutputFile *fo) |
1288 | 0 | { |
1289 | 0 | ARM_updateLoader(fo); // not ARM specific; (no 32-bit immediates) |
1290 | 0 | } |
1291 | | |
1292 | | void PackLinuxElf32mipseb::updateLoader(OutputFile *fo) |
1293 | 0 | { |
1294 | 0 | ARM_updateLoader(fo); // not ARM specific; (no 32-bit immediates) |
1295 | 0 | } |
1296 | | |
1297 | | void PackLinuxElf32::updateLoader(OutputFile * /*fo*/) |
1298 | 0 | { |
1299 | 0 | unsigned start = linker->getSymbolOffset("_start"); |
1300 | 0 | unsigned vbase = get_te32(&elfout.phdr[C_TEXT].p_vaddr); |
1301 | 0 | set_te32(&elfout.ehdr.e_entry, start + sz_pack2 + vbase); |
1302 | 0 | } |
1303 | | |
1304 | | void PackLinuxElf64::updateLoader(OutputFile * /*fo*/) |
1305 | 0 | { |
1306 | 0 | if (xct_off) { |
1307 | 0 | return; // FIXME elfout has no values at all |
1308 | 0 | } |
1309 | 0 | upx_uint64_t const vbase = get_te64(&elfout.phdr[C_TEXT].p_vaddr); |
1310 | 0 | unsigned start = linker->getSymbolOffset("_start"); |
1311 | |
|
1312 | 0 | if (get_te16(&elfout.ehdr.e_machine)==Elf64_Ehdr::EM_PPC64 |
1313 | 0 | && elfout.ehdr.e_ident[Elf64_Ehdr::EI_DATA]==Elf64_Ehdr::ELFDATA2MSB) { |
1314 | 0 | unsigned descr = linker->getSymbolOffset("entry_descr"); |
1315 | | |
1316 | | // External relocation of PPC64 function descriptor. |
1317 | 0 | upx_uint64_t dot_entry = start + sz_pack2 + vbase; |
1318 | 0 | upx_byte *p = getLoader(); |
1319 | |
|
1320 | 0 | set_te64(&p[descr], dot_entry); |
1321 | | // Kernel 3.16.0 (2017-09-19) uses start, not descr |
1322 | 0 | set_te64(&elfout.ehdr.e_entry, start + sz_pack2 + vbase); |
1323 | 0 | } |
1324 | 0 | else { |
1325 | 0 | set_te64(&elfout.ehdr.e_entry, start + sz_pack2 + vbase); |
1326 | 0 | } |
1327 | 0 | } |
1328 | | |
1329 | | PackLinuxElf32ppc::PackLinuxElf32ppc(InputFile *f) |
1330 | 16.4k | : super(f) |
1331 | 16.4k | { |
1332 | 16.4k | e_machine = Elf32_Ehdr::EM_PPC; |
1333 | 16.4k | ei_class = Elf32_Ehdr::ELFCLASS32; |
1334 | 16.4k | ei_data = Elf32_Ehdr::ELFDATA2MSB; |
1335 | 16.4k | ei_osabi = Elf32_Ehdr::ELFOSABI_LINUX; |
1336 | 16.4k | } |
1337 | | |
1338 | | PackLinuxElf32ppc::~PackLinuxElf32ppc() |
1339 | 16.4k | { |
1340 | 16.4k | } |
1341 | | |
1342 | | Linker* PackLinuxElf32ppc::newLinker() const |
1343 | 0 | { |
1344 | 0 | return new ElfLinkerPpc32; |
1345 | 0 | } |
1346 | | |
1347 | | PackLinuxElf64ppcle::PackLinuxElf64ppcle(InputFile *f) |
1348 | 14.5k | : super(f), lg2_page(16), page_size(1u<<lg2_page) |
1349 | 14.5k | { |
1350 | 14.5k | e_machine = Elf64_Ehdr::EM_PPC64; |
1351 | 14.5k | ei_class = Elf64_Ehdr::ELFCLASS64; |
1352 | 14.5k | ei_data = Elf64_Ehdr::ELFDATA2LSB; |
1353 | 14.5k | ei_osabi = Elf64_Ehdr::ELFOSABI_LINUX; |
1354 | 14.5k | } |
1355 | | |
1356 | | PackLinuxElf64ppc::PackLinuxElf64ppc(InputFile *f) |
1357 | 16.3k | : super(f), lg2_page(16), page_size(1u<<lg2_page) |
1358 | 16.3k | { |
1359 | 16.3k | e_machine = Elf64_Ehdr::EM_PPC64; |
1360 | 16.3k | ei_class = Elf64_Ehdr::ELFCLASS64; |
1361 | 16.3k | ei_data = Elf64_Ehdr::ELFDATA2MSB; |
1362 | 16.3k | ei_osabi = Elf32_Ehdr::ELFOSABI_LINUX; |
1363 | 16.3k | } |
1364 | | |
1365 | | PackLinuxElf64ppcle::~PackLinuxElf64ppcle() |
1366 | 14.5k | { |
1367 | 14.5k | } |
1368 | | |
1369 | | PackLinuxElf64ppc::~PackLinuxElf64ppc() |
1370 | 14.5k | { |
1371 | 14.5k | } |
1372 | | |
1373 | | Linker* PackLinuxElf64ppcle::newLinker() const |
1374 | 0 | { |
1375 | 0 | return new ElfLinkerPpc64le; |
1376 | 0 | } |
1377 | | |
1378 | | Linker* PackLinuxElf64ppc::newLinker() const |
1379 | 0 | { |
1380 | 0 | return new ElfLinkerPpc64; |
1381 | 0 | } |
1382 | | |
1383 | | PackLinuxElf64amd::PackLinuxElf64amd(InputFile *f) |
1384 | 21.6k | : super(f) |
1385 | 21.6k | { |
1386 | | // Why did PackLinuxElf64Le set lg2_page = 16 ? |
1387 | | // It causes trouble for check_pt_dynamic() from canPack(). |
1388 | 21.6k | lg2_page = 12; page_size = 1u<<lg2_page; |
1389 | 21.6k | e_machine = Elf64_Ehdr::EM_X86_64; |
1390 | 21.6k | ei_class = Elf64_Ehdr::ELFCLASS64; |
1391 | 21.6k | ei_data = Elf64_Ehdr::ELFDATA2LSB; |
1392 | 21.6k | ei_osabi = Elf32_Ehdr::ELFOSABI_LINUX; |
1393 | 21.6k | } |
1394 | | |
1395 | | PackLinuxElf64arm::PackLinuxElf64arm(InputFile *f) |
1396 | 16.6k | : super(f) |
1397 | 16.6k | { |
1398 | 16.6k | e_machine = Elf64_Ehdr::EM_AARCH64; |
1399 | 16.6k | ei_class = Elf64_Ehdr::ELFCLASS64; |
1400 | 16.6k | ei_data = Elf64_Ehdr::ELFDATA2LSB; |
1401 | 16.6k | ei_osabi = Elf32_Ehdr::ELFOSABI_LINUX; |
1402 | 16.6k | } |
1403 | | |
1404 | | PackLinuxElf64amd::~PackLinuxElf64amd() |
1405 | 19.5k | { |
1406 | 19.5k | } |
1407 | | |
1408 | | PackLinuxElf64arm::~PackLinuxElf64arm() |
1409 | 16.6k | { |
1410 | 16.6k | } |
1411 | | |
1412 | | void PackLinuxElf32x86::addStubEntrySections(Filter const *ft, unsigned m_decompr) |
1413 | 0 | { |
1414 | 0 | (void)m_decompr; // FIXME |
1415 | 0 | int const n_mru = ft->n_mru; // FIXME: belongs to filter? packerf? |
1416 | | |
1417 | | // Rely on "+80CXXXX" [etc] in getDecompressorSections() packer_c.cpp */ |
1418 | | // // Here is a quick summary of the format of the output file: |
1419 | | // linker->setLoaderAlignOffset( |
1420 | | // // Elf32_Ehdr |
1421 | | // sizeof(elfout.ehdr) + |
1422 | | // // Elf32_Phdr: 1 for exec86, 2 for sh86, 3 for elf86 |
1423 | | // (get_te16(&elfout.ehdr.e_phentsize) * get_te16(&elfout.ehdr.e_phnum)) + |
1424 | | // // checksum UPX! lsize version format |
1425 | | // sizeof(l_info) + |
1426 | | // // PT_DYNAMIC with DT_NEEDED "forwarded" from original file |
1427 | | // ((get_te16(&elfout.ehdr.e_phnum)==3) |
1428 | | // ? (unsigned) get_te32(&elfout.phdr[C_NOTE].p_memsz) |
1429 | | // : 0) + |
1430 | | // // p_progid, p_filesize, p_blocksize |
1431 | | // sizeof(p_info) + |
1432 | | // // compressed data |
1433 | | // b_len + ph.c_len ); |
1434 | | |
1435 | | // entry to stub |
1436 | 0 | addLoader("LEXEC000", nullptr); |
1437 | |
|
1438 | 0 | if (ft->id) { |
1439 | 0 | { // decompr, unfilter are separate |
1440 | 0 | addLoader("LXUNF000", nullptr); |
1441 | 0 | addLoader("LXUNF002", nullptr); |
1442 | 0 | if (0x80==(ft->id & 0xF0)) { |
1443 | 0 | if (256==n_mru) { |
1444 | 0 | addLoader("MRUBYTE0", nullptr); |
1445 | 0 | } |
1446 | 0 | else if (n_mru) { |
1447 | 0 | addLoader("LXMRU005", nullptr); |
1448 | 0 | } |
1449 | 0 | if (n_mru) { |
1450 | 0 | addLoader("LXMRU006", nullptr); |
1451 | 0 | } |
1452 | 0 | else { |
1453 | 0 | addLoader("LXMRU007", nullptr); |
1454 | 0 | } |
1455 | 0 | } |
1456 | 0 | else if (0x40==(ft->id & 0xF0)) { |
1457 | 0 | addLoader("LXUNF008", nullptr); |
1458 | 0 | } |
1459 | 0 | addLoader("LXUNF010", nullptr); |
1460 | 0 | } |
1461 | 0 | if (n_mru) { |
1462 | 0 | addLoader("LEXEC009", nullptr); |
1463 | 0 | } |
1464 | 0 | } |
1465 | 0 | addLoader("LEXEC010", nullptr); |
1466 | 0 | addLoader(getDecompressorSections(), nullptr); |
1467 | 0 | addLoader("LEXEC015", nullptr); |
1468 | 0 | if (ft->id) { |
1469 | 0 | { // decompr, unfilter are separate |
1470 | 0 | if (0x80!=(ft->id & 0xF0)) { |
1471 | 0 | addLoader("LXUNF042", nullptr); |
1472 | 0 | } |
1473 | 0 | } |
1474 | 0 | addFilter32(ft->id); |
1475 | 0 | { // decompr, unfilter are separate |
1476 | 0 | if (0x80==(ft->id & 0xF0)) { |
1477 | 0 | if (0==n_mru) { |
1478 | 0 | addLoader("LXMRU058", nullptr); |
1479 | 0 | } |
1480 | 0 | } |
1481 | 0 | addLoader("LXUNF035", nullptr); |
1482 | 0 | } |
1483 | 0 | } |
1484 | 0 | else { |
1485 | 0 | addLoader("LEXEC017", nullptr); |
1486 | 0 | } |
1487 | |
|
1488 | 0 | addLoader("IDENTSTR", nullptr); |
1489 | 0 | addLoader("+40,LEXEC020", nullptr); |
1490 | 0 | addLoader("FOLDEXEC", nullptr); |
1491 | 0 | } |
1492 | | |
1493 | | void PackLinuxElf32x86::defineSymbols(Filter const *const ft) |
1494 | 0 | { |
1495 | 0 | PackLinuxElf32::defineSymbols(ft); |
1496 | |
|
1497 | 0 | if (0x80==(ft->id & 0xF0)) { |
1498 | 0 | int const mru = ft->n_mru ? 1+ ft->n_mru : 0; |
1499 | 0 | if (mru && mru!=256) { |
1500 | 0 | unsigned const is_pwr2 = (0==((mru -1) & mru)); |
1501 | 0 | linker->defineSymbol("NMRU", mru - is_pwr2); |
1502 | 0 | } |
1503 | 0 | } |
1504 | 0 | } |
1505 | | |
1506 | | void |
1507 | | PackLinuxElf32::buildLinuxLoader( |
1508 | | upx_byte const *const proto, |
1509 | | unsigned const szproto, |
1510 | | upx_byte const *const fold, |
1511 | | unsigned const szfold, |
1512 | | Filter const *ft |
1513 | | ) |
1514 | 0 | { |
1515 | 0 | MemBuffer mb_cprLoader; |
1516 | 0 | unsigned sz_cpr = 0; |
1517 | 0 | unsigned sz_unc = 0; |
1518 | 0 | unsigned method = 0; |
1519 | 0 | upx_byte const *uncLoader = nullptr; |
1520 | |
|
1521 | 0 | if (0 < szfold) { |
1522 | 0 | if (xct_off // shlib |
1523 | 0 | && ( this->e_machine==Elf32_Ehdr::EM_ARM |
1524 | 0 | || this->e_machine==Elf32_Ehdr::EM_386) |
1525 | 0 | ) { |
1526 | 0 | initLoader(fold, szfold); |
1527 | | // Typical layout of 'sections' in compressed stub code for shared library: |
1528 | | // SO_HEAD |
1529 | | // ptr_NEXT |
1530 | | // EXP_HEAD NRV getbit(), copy |
1531 | | // NRV2B etc: daisy chain of de-compressor for each method used |
1532 | | // EXP_TAIL FIXME: unfilter |
1533 | | // SO_TAIL |
1534 | | // SO_MAIN C-language supervision based on PT_LOADs |
1535 | 0 | char sec[200]; memset(sec, 0, sizeof(sec)); // debug convenience |
1536 | 0 | int len = 0; |
1537 | 0 | unsigned m_decompr = methods_used | (1u << (0xFF & ph_forced_method(ph.method))); |
1538 | 0 | len += snprintf(sec, sizeof(sec), "%s", "SO_HEAD,ptr_NEXT,EXP_HEAD"); |
1539 | | |
1540 | | // Start of dasiy-chain fall-through. |
1541 | 0 | if (((1u<<M_NRV2B_LE32)|(1u<<M_NRV2B_8)|(1u<<M_NRV2B_LE16)) & m_decompr) { |
1542 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2B"); |
1543 | 0 | } |
1544 | 0 | if (((1u<<M_NRV2D_LE32)|(1u<<M_NRV2D_8)|(1u<<M_NRV2D_LE16)) & m_decompr) { |
1545 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2D"); |
1546 | 0 | } |
1547 | 0 | if (((1u<<M_NRV2E_LE32)|(1u<<M_NRV2E_8)|(1u<<M_NRV2E_LE16)) & m_decompr) { |
1548 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2E"); |
1549 | 0 | } |
1550 | 0 | if (((1u<<M_LZMA)) & m_decompr) { |
1551 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", |
1552 | 0 | "LZMA_DAISY,LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"); |
1553 | 0 | } |
1554 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "EXP_TAIL"); |
1555 | | // End of daisy-chain fall-through. |
1556 | | |
1557 | | // MIPS directly calls memfd_create |
1558 | 0 | if (this->e_machine != Elf32_Ehdr::EM_MIPS) { |
1559 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", |
1560 | 0 | (sec_arm_attr || is_asl) |
1561 | 0 | ? "HUMF_A,UMF_ANDROID" |
1562 | 0 | : "HUMF_L,UMF_LINUX"); |
1563 | 0 | } |
1564 | 0 | if (hasLoaderSection("STRCON")) { |
1565 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "STRCON"); |
1566 | 0 | } |
1567 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "SO_TAIL,SO_MAIN"); |
1568 | 0 | (void)len; // Pacify the anal-retentive static analyzer which hates a good idiom. |
1569 | 0 | NO_printf("\n%s\n", sec); |
1570 | 0 | addLoader(sec, nullptr); |
1571 | 0 | relocateLoader(); |
1572 | 0 | { |
1573 | 0 | int sz_unc_int; |
1574 | 0 | uncLoader = linker->getLoader(&sz_unc_int); |
1575 | 0 | sz_unc = sz_unc_int; |
1576 | 0 | } |
1577 | 0 | method = M_NRV2B_LE32; // requires unaligned fetch |
1578 | 0 | if (this->e_machine==Elf32_Ehdr::EM_ARM) |
1579 | 0 | method = M_NRV2B_8; //only ARM v6 and above has unaligned fetch |
1580 | 0 | } // end shlib (folded portion) |
1581 | 0 | else if (this->e_machine==Elf32_Ehdr::EM_386 |
1582 | 0 | || this->e_machine==Elf32_Ehdr::EM_ARM |
1583 | 0 | || this->e_machine==Elf32_Ehdr::EM_PPC |
1584 | 0 | || this->e_machine==Elf32_Ehdr::EM_MIPS |
1585 | 0 | ) { // main program with ELF2 de-compressor (folded portion) |
1586 | 0 | initLoader(fold, szfold); |
1587 | 0 | char sec[200]; memset(sec, 0, sizeof(sec)); // debug convenience |
1588 | 0 | int len = 0; |
1589 | 0 | unsigned m_decompr = methods_used | (1u << (0xFF & ph_forced_method(ph.method))); |
1590 | 0 | len += snprintf(sec, sizeof(sec), "%s", ".text,EXP_HEAD"); |
1591 | 0 | if (((1u<<M_NRV2B_LE32)|(1u<<M_NRV2B_8)|(1u<<M_NRV2B_LE16)) & m_decompr) { |
1592 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2B"); |
1593 | 0 | } |
1594 | 0 | if (((1u<<M_NRV2D_LE32)|(1u<<M_NRV2D_8)|(1u<<M_NRV2D_LE16)) & m_decompr) { |
1595 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2D"); |
1596 | 0 | } |
1597 | 0 | if (((1u<<M_NRV2E_LE32)|(1u<<M_NRV2E_8)|(1u<<M_NRV2E_LE16)) & m_decompr) { |
1598 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2E"); |
1599 | 0 | } |
1600 | 0 | if (((1u<<M_LZMA)) & m_decompr) { |
1601 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", |
1602 | 0 | "LZMA_DAISY,LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"); |
1603 | 0 | } |
1604 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "EXP_TAIL"); |
1605 | | |
1606 | | // $ARCH-linux.elf-main2.c calls upx_mmap_and_fd, not direct memfd_create |
1607 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", |
1608 | 0 | (sec_arm_attr || is_asl) |
1609 | 0 | ? "HUMF_A,UMF_ANDROID" |
1610 | 0 | : "HUMF_L,UMF_LINUX"); |
1611 | 0 | if (hasLoaderSection("SYSCALLS")) { |
1612 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "SYSCALLS"); |
1613 | 0 | } |
1614 | 0 | (void)len; // Pacify the anal-retentive static analyzer which hates a good idiom. |
1615 | 0 | NO_printf("\n%s\n", sec); |
1616 | 0 | addLoader(sec, nullptr); |
1617 | 0 | relocateLoader(); |
1618 | 0 | { |
1619 | 0 | int sz_unc_int; |
1620 | 0 | uncLoader = linker->getLoader(&sz_unc_int); |
1621 | 0 | sz_unc = sz_unc_int; |
1622 | 0 | } |
1623 | 0 | method = M_NRV2B_LE32; // requires unaligned fetch |
1624 | 0 | if (this->e_machine==Elf32_Ehdr::EM_ARM) |
1625 | 0 | method = M_NRV2B_8; //only ARM v6 and above has unaligned fetch |
1626 | 0 | } |
1627 | 0 | else { // main program with ELF1 de-compressor (folded portion) |
1628 | 0 | cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold; |
1629 | 0 | unsigned fold_hdrlen = usizeof(hf->ehdr) + |
1630 | 0 | get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum); |
1631 | 0 | if (this->e_machine==Elf32_Ehdr::EM_MIPS) { |
1632 | 0 | fold_hdrlen = upx::umax(fold_hdrlen, (unsigned)0x80); |
1633 | 0 | } |
1634 | 0 | uncLoader = fold_hdrlen + fold; |
1635 | 0 | sz_unc = ((szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen)); |
1636 | 0 | method = ph.method; |
1637 | 0 | } |
1638 | |
|
1639 | 0 | struct b_info h; memset(&h, 0, sizeof(h)); |
1640 | 0 | h.b_method = method; |
1641 | | // _Ehdr and _Phdr are NOT filtered, so Leave h.b_ftid and h.b_cto8 as zero. |
1642 | |
|
1643 | 0 | mb_cprLoader.allocForCompression(sizeof(h) + sz_unc); |
1644 | 0 | unsigned char *const cprLoader = (unsigned char *)mb_cprLoader; // less typing |
1645 | |
|
1646 | 0 | h.sz_unc = sz_unc; |
1647 | 0 | h.sz_cpr = mb_cprLoader.getSize(); // max that upx_compress may use |
1648 | 0 | { |
1649 | 0 | int r = upx_compress(uncLoader, sz_unc, sizeof(h) + cprLoader, &sz_cpr, |
1650 | 0 | nullptr, ph_forced_method(method), 10, nullptr, nullptr ); |
1651 | 0 | h.sz_cpr = sz_cpr; // actual length used |
1652 | 0 | if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc) |
1653 | 0 | throwInternalError("loader compression failed"); |
1654 | 0 | } |
1655 | 0 | set_te32(&h.sz_cpr, h.sz_cpr); |
1656 | 0 | set_te32(&h.sz_unc, h.sz_unc); |
1657 | 0 | memcpy(cprLoader, &h, sizeof(h)); // cprLoader will become FOLDEXEC |
1658 | 0 | } // end (0 < szfold) |
1659 | | |
1660 | 0 | initLoader(proto, szproto, -1, sz_cpr); |
1661 | 0 | NO_printf("FOLDEXEC unc=%#x cpr=%#x\n", sz_unc, sz_cpr); |
1662 | 0 | linker->addSection("FOLDEXEC", mb_cprLoader, sizeof(b_info) + sz_cpr, 0); |
1663 | 0 | if (xct_off // shlib |
1664 | 0 | && (this->e_machine==Elf32_Ehdr::EM_NONE |
1665 | 0 | || this->e_machine==Elf32_Ehdr::EM_386 |
1666 | 0 | || this->e_machine==Elf32_Ehdr::EM_ARM |
1667 | 0 | || this->e_machine==Elf32_Ehdr::EM_PPC |
1668 | 0 | || this->e_machine==Elf32_Ehdr::EM_MIPS |
1669 | 0 | ) |
1670 | 0 | ) { // shlib with ELF2 de-compressor |
1671 | 0 | addLoader("ELFMAINX"); |
1672 | 0 | addLoader((sec_arm_attr || is_asl) |
1673 | 0 | ? "HUMF_A,UMF_ANDROID" |
1674 | 0 | : "HUMF_L,UMF_LINUX"); |
1675 | 0 | addLoader("ELFMAINZ,FOLDEXEC,IDENTSTR"); |
1676 | 0 | } |
1677 | 0 | else if (this->e_machine==Elf32_Ehdr::EM_NONE |
1678 | 0 | || this->e_machine==Elf32_Ehdr::EM_386 |
1679 | 0 | || this->e_machine==Elf32_Ehdr::EM_ARM |
1680 | 0 | || this->e_machine==Elf32_Ehdr::EM_PPC |
1681 | 0 | || this->e_machine==Elf32_Ehdr::EM_MIPS |
1682 | 0 | ) { // main program with ELF2 de-compressor |
1683 | 0 | addLoader("ELFMAINX"); |
1684 | 0 | if (this->e_machine==Elf32_Ehdr::EM_ARM) { // hardware is more problematic |
1685 | 0 | if (opt->o_unix.catch_sigsegv && hasLoaderSection("ELFSIGSEGV")) |
1686 | 0 | addLoader("ELFSIGSEGV"); |
1687 | 0 | addLoader("ELFMAINX2"); |
1688 | 0 | } |
1689 | | // Only if $ARCH-linux.elf-entry.S calls upx_mmap_and_fd instead of memfd_create |
1690 | 0 | if (this->e_machine != Elf32_Ehdr::EM_PPC |
1691 | 0 | && this->e_machine != Elf32_Ehdr::EM_MIPS) |
1692 | 0 | addLoader((sec_arm_attr || is_asl) |
1693 | 0 | ? "HUMF_A,UMF_ANDROID" |
1694 | 0 | : "HUMF_L,UMF_LINUX"); |
1695 | 0 | addLoader("ELFMAINZ,FOLDEXEC,IDENTSTR"); |
1696 | 0 | defineSymbols(ft); |
1697 | 0 | } |
1698 | 0 | else { // main program with ELF1 de-compressor |
1699 | 0 | addStubEntrySections(ft, methods_used | (1u << (0xFF & ph_forced_method(ph.method))) ); |
1700 | 0 | if (!xct_off) { // main program |
1701 | 0 | defineSymbols(ft); |
1702 | 0 | } |
1703 | 0 | } |
1704 | 0 | relocateLoader(); |
1705 | 0 | } |
1706 | | |
1707 | | void |
1708 | | PackLinuxElf64::buildLinuxLoader( |
1709 | | upx_byte const *const proto, |
1710 | | unsigned const szproto, |
1711 | | upx_byte const *const fold, |
1712 | | unsigned const szfold, |
1713 | | Filter const *ft |
1714 | | ) |
1715 | 0 | { |
1716 | 0 | MemBuffer mb_cprLoader; |
1717 | 0 | unsigned sz_cpr = 0; |
1718 | 0 | unsigned sz_unc = 0; |
1719 | 0 | unsigned method = 0; |
1720 | 0 | upx_byte const *uncLoader = nullptr; |
1721 | |
|
1722 | 0 | if (0 < szfold) { |
1723 | 0 | if (xct_off // shlib |
1724 | 0 | && ( this->e_machine==Elf64_Ehdr::EM_X86_64 |
1725 | 0 | || this->e_machine==Elf64_Ehdr::EM_AARCH64) |
1726 | 0 | ) { |
1727 | 0 | initLoader(fold, szfold); |
1728 | | // Typical layout of 'sections' in compressed stub code for shared library: |
1729 | | // SO_HEAD |
1730 | | // ptr_NEXT |
1731 | | // EXP_HEAD NRV getbit(), copy |
1732 | | // NRV2B etc: daisy chain of de-compressor for each method used |
1733 | | // EXP_TAIL FIXME: unfilter |
1734 | | // SO_TAIL |
1735 | | // SO_MAIN C-language supervision based on PT_LOADs |
1736 | 0 | char sec[200]; memset(sec, 0, sizeof(sec)); // debug convenience |
1737 | 0 | int len = 0; |
1738 | 0 | unsigned m_decompr = methods_used | (1u << (0xFF & ph_forced_method(ph.method))); |
1739 | 0 | len += snprintf(sec, sizeof(sec), "%s", "SO_HEAD,ptr_NEXT,EXP_HEAD"); |
1740 | | |
1741 | | // Start of dasiy-chain fall-through. |
1742 | 0 | if (((1u<<M_NRV2B_LE32)|(1u<<M_NRV2B_8)|(1u<<M_NRV2B_LE16)) & m_decompr) { |
1743 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2B"); |
1744 | 0 | } |
1745 | 0 | if (((1u<<M_NRV2D_LE32)|(1u<<M_NRV2D_8)|(1u<<M_NRV2D_LE16)) & m_decompr) { |
1746 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2D"); |
1747 | 0 | } |
1748 | 0 | if (((1u<<M_NRV2E_LE32)|(1u<<M_NRV2E_8)|(1u<<M_NRV2E_LE16)) & m_decompr) { |
1749 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2E"); |
1750 | 0 | } |
1751 | 0 | if (((1u<<M_LZMA)) & m_decompr) { |
1752 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", |
1753 | 0 | "LZMA_DAISY,LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"); |
1754 | 0 | } |
1755 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "EXP_TAIL"); |
1756 | | // End of daisy-chain fall-through. |
1757 | | |
1758 | | // Android on EM_AARCH64 has memfd_create(), so UMF_ANDROID not needed. |
1759 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "HUMF_L,UMF_LINUX"); |
1760 | 0 | if (hasLoaderSection("STRCON")) { |
1761 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "STRCON"); |
1762 | 0 | } |
1763 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "SO_TAIL,SO_MAIN"); |
1764 | 0 | (void)len; // Pacify the anal-retentive static analyzer which hates a good idiom. |
1765 | 0 | NO_printf("\n%s\n", sec); |
1766 | 0 | addLoader(sec, nullptr); |
1767 | 0 | relocateLoader(); |
1768 | 0 | { |
1769 | 0 | int sz_unc_int; |
1770 | 0 | uncLoader = linker->getLoader(&sz_unc_int); |
1771 | 0 | sz_unc = sz_unc_int; |
1772 | 0 | } |
1773 | 0 | method = M_NRV2B_LE32; // requires unaligned fetch |
1774 | 0 | } |
1775 | 0 | else if (this->e_machine==Elf32_Ehdr::EM_NONE |
1776 | 0 | || this->e_machine==Elf64_Ehdr::EM_X86_64 |
1777 | 0 | || this->e_machine==Elf64_Ehdr::EM_AARCH64 |
1778 | 0 | || this->e_machine==Elf64_Ehdr::EM_PPC64 |
1779 | 0 | ) { // main program with ELF2 de-compressor (folded portion) |
1780 | 0 | initLoader(fold, szfold); |
1781 | 0 | char sec[200]; memset(sec, 0, sizeof(sec)); // debug convenience |
1782 | 0 | int len = 0; |
1783 | 0 | unsigned m_decompr = methods_used | (1u << (0xFF & ph_forced_method(ph.method))); |
1784 | 0 | len += snprintf(sec, sizeof(sec), "%s", ".text,EXP_HEAD"); |
1785 | 0 | if (((1u<<M_NRV2B_LE32)|(1u<<M_NRV2B_8)|(1u<<M_NRV2B_LE16)) & m_decompr) { |
1786 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2B"); |
1787 | 0 | } |
1788 | 0 | if (((1u<<M_NRV2D_LE32)|(1u<<M_NRV2D_8)|(1u<<M_NRV2D_LE16)) & m_decompr) { |
1789 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2D"); |
1790 | 0 | } |
1791 | 0 | if (((1u<<M_NRV2E_LE32)|(1u<<M_NRV2E_8)|(1u<<M_NRV2E_LE16)) & m_decompr) { |
1792 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "NRV2E"); |
1793 | 0 | } |
1794 | 0 | if (((1u<<M_LZMA)) & m_decompr) { |
1795 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", |
1796 | 0 | "LZMA_DAISY,LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"); |
1797 | 0 | } |
1798 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "EXP_TAIL"); |
1799 | 0 | if (hasLoaderSection("SYSCALLS")) { |
1800 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "SYSCALLS"); |
1801 | 0 | } |
1802 | 0 | if (hasLoaderSection("STRCON")) { |
1803 | 0 | len += snprintf(&sec[len], sizeof(sec) - len, ",%s", "STRCON"); |
1804 | 0 | } |
1805 | 0 | (void)len; |
1806 | 0 | NO_printf("\n%s\n", sec); |
1807 | 0 | addLoader(sec, nullptr); |
1808 | 0 | relocateLoader(); |
1809 | 0 | { |
1810 | 0 | int sz_unc_int; |
1811 | 0 | uncLoader = linker->getLoader(&sz_unc_int); |
1812 | 0 | sz_unc = sz_unc_int; |
1813 | 0 | } |
1814 | 0 | method = M_NRV2B_LE32; // requires unaligned fetch |
1815 | 0 | } |
1816 | 0 | else { // not shlib: main program with ELF1 de-compressor |
1817 | 0 | cprElfHdr1 const *hf = (cprElfHdr1 const *)fold; |
1818 | 0 | e_type = get_te16(&hf->ehdr.e_type); |
1819 | 0 | if (ET_REL == e_type) { |
1820 | 0 | initLoader(fold, szfold); |
1821 | 0 | addLoader(".text", nullptr); |
1822 | 0 | relocateLoader(); |
1823 | 0 | int sz_unc_int(0); |
1824 | 0 | uncLoader = linker->getLoader(&sz_unc_int); |
1825 | 0 | sz_unc = sz_unc_int; |
1826 | 0 | } |
1827 | 0 | else if (ET_EXEC == e_type) { |
1828 | 0 | hf = (cprElfHdr1 const *)fold; |
1829 | 0 | unsigned fold_hdrlen = usizeof(hf->ehdr) + |
1830 | 0 | get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum); |
1831 | 0 | if (this->e_machine==Elf64_Ehdr::EM_X86_64) { |
1832 | 0 | fold_hdrlen = get_te64(&hf->ehdr.e_entry); |
1833 | 0 | } |
1834 | 0 | uncLoader = &fold[fold_hdrlen]; |
1835 | 0 | sz_unc = ((szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen)); |
1836 | 0 | } |
1837 | 0 | method = ph.method; |
1838 | 0 | } |
1839 | |
|
1840 | 0 | struct b_info h; memset(&h, 0, sizeof(h)); |
1841 | 0 | h.b_method = method; |
1842 | | // _Ehdr and _Phdr are NOT filtered, so Leave h.b_ftid and h.b_cto8 as zero. |
1843 | |
|
1844 | 0 | mb_cprLoader.allocForCompression(sizeof(h) + sz_unc); |
1845 | 0 | unsigned char *const cprLoader = (unsigned char *)mb_cprLoader; // less typing |
1846 | |
|
1847 | 0 | h.sz_unc = sz_unc; |
1848 | 0 | h.sz_cpr = mb_cprLoader.getSize(); // max that upx_compress may use |
1849 | 0 | { |
1850 | 0 | int r = upx_compress(uncLoader, sz_unc, sizeof(h) + cprLoader, &sz_cpr, |
1851 | 0 | nullptr, ph_forced_method(method), 10, nullptr, nullptr ); |
1852 | 0 | h.sz_cpr = sz_cpr; // actual length used |
1853 | 0 | if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc) |
1854 | 0 | throwInternalError("loader compression failed"); |
1855 | 0 | } |
1856 | 0 | set_te32(&h.sz_cpr, h.sz_cpr); |
1857 | 0 | set_te32(&h.sz_unc, h.sz_unc); |
1858 | 0 | memcpy(cprLoader, &h, sizeof(h)); // cprLoader will become FOLDEXEC |
1859 | 0 | } // end (0 < szfold) |
1860 | | |
1861 | 0 | initLoader(proto, szproto, -1, sz_cpr); |
1862 | 0 | NO_printf("FOLDEXEC unc=%#x cpr=%#x\n", sz_unc, sz_cpr); |
1863 | 0 | linker->addSection("FOLDEXEC", mb_cprLoader, sizeof(b_info) + sz_cpr, 0); |
1864 | 0 | if (xct_off |
1865 | 0 | && (this->e_machine==Elf64_Ehdr::EM_NONE |
1866 | 0 | || this->e_machine==Elf64_Ehdr::EM_X86_64 |
1867 | 0 | || this->e_machine==Elf64_Ehdr::EM_AARCH64 |
1868 | 0 | || this->e_machine==Elf64_Ehdr::EM_PPC64 |
1869 | 0 | ) |
1870 | 0 | ) { |
1871 | 0 | addLoader("ELFMAINX,ELFMAINZ,FOLDEXEC,IDENTSTR"); |
1872 | 0 | } // shlib |
1873 | 0 | else if (this->e_machine==Elf32_Ehdr::EM_NONE |
1874 | 0 | || this->e_machine==Elf64_Ehdr::EM_X86_64 |
1875 | 0 | || this->e_machine==Elf64_Ehdr::EM_AARCH64 |
1876 | 0 | || this->e_machine==Elf64_Ehdr::EM_PPC64 |
1877 | 0 | ) { // main program with ELF2 de-compressor |
1878 | 0 | addLoader("ELFMAINX"); |
1879 | | // NYI for PPC64 { |
1880 | 0 | if (opt->o_unix.catch_sigsegv && hasLoaderSection("ELFSIGSEGV")) |
1881 | 0 | addLoader("ELFSIGSEGV"); |
1882 | 0 | if (this->e_machine!=Elf64_Ehdr::EM_PPC64) |
1883 | 0 | addLoader("ELFMAINX2"); |
1884 | | // } end NYI for PPC64 |
1885 | 0 | addLoader("ELFMAINZ,FOLDEXEC,IDENTSTR"); |
1886 | 0 | if (this->e_machine==Elf64_Ehdr::EM_PPC64 |
1887 | 0 | && ehdri.e_ident[Elf64_Ehdr::EI_DATA]==Elf64_Ehdr::ELFDATA2MSB) { |
1888 | 0 | addLoader("ELFMAINZe"); |
1889 | 0 | } |
1890 | 0 | if (!xct_off) { // main program |
1891 | 0 | defineSymbols(ft); |
1892 | 0 | } |
1893 | 0 | } |
1894 | 0 | else { // main program with ELF1 de-compressor |
1895 | 0 | addStubEntrySections(ft, methods_used | (1u << (0xFF & ph_forced_method(ph.method))) ); |
1896 | 0 | if (!xct_off) { // main program |
1897 | 0 | defineSymbols(ft); |
1898 | 0 | } |
1899 | 0 | } |
1900 | 0 | relocateLoader(); |
1901 | 0 | } |
1902 | | |
1903 | | void |
1904 | | PackLinuxElf64amd::defineSymbols(Filter const *ft) |
1905 | 0 | { |
1906 | 0 | PackLinuxElf64::defineSymbols(ft); |
1907 | 0 | } |
1908 | | |
1909 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1910 | | #include "stub/i386-linux.elf-entry.h" |
1911 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1912 | | #include "stub/i386-linux.elf-so_entry.h" |
1913 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1914 | | #include "stub/i386-linux.elf-fold.h" |
1915 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1916 | | #include "stub/i386-linux.elf-so_fold.h" |
1917 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1918 | | #include "stub/i386-linux.shlib-init.h" |
1919 | | |
1920 | | void |
1921 | | PackLinuxElf32x86::buildLoader(const Filter *ft) |
1922 | 0 | { |
1923 | 0 | if (0!=xct_off) { // shared library |
1924 | 0 | buildLinuxLoader( |
1925 | 0 | stub_i386_linux_elf_so_entry, sizeof(stub_i386_linux_elf_so_entry), |
1926 | 0 | stub_i386_linux_elf_so_fold, sizeof(stub_i386_linux_elf_so_fold), ft); |
1927 | 0 | return; |
1928 | 0 | } |
1929 | 0 | unsigned char tmp[sizeof(stub_i386_linux_elf_fold)]; |
1930 | 0 | memcpy(tmp, stub_i386_linux_elf_fold, sizeof(stub_i386_linux_elf_fold)); |
1931 | 0 | checkPatch(nullptr, 0, 0, 0); // reset |
1932 | 0 | if (opt->o_unix.is_ptinterp) { |
1933 | 0 | unsigned j; |
1934 | 0 | for (j = 0; j < sizeof(stub_i386_linux_elf_fold)-1; ++j) { |
1935 | 0 | if (0x60==tmp[ j] |
1936 | 0 | && 0x47==tmp[1+j] ) { |
1937 | | /* put INC EDI before PUSHA: inhibits auxv_up for PT_INTERP */ |
1938 | 0 | tmp[ j] = 0x47; |
1939 | 0 | tmp[1+j] = 0x60; |
1940 | 0 | break; |
1941 | 0 | } |
1942 | 0 | } |
1943 | 0 | } |
1944 | 0 | buildLinuxLoader( |
1945 | 0 | stub_i386_linux_elf_entry, sizeof(stub_i386_linux_elf_entry), |
1946 | 0 | tmp, sizeof(stub_i386_linux_elf_fold), ft ); |
1947 | 0 | } |
1948 | | |
1949 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1950 | | #include "stub/i386-bsd.elf-entry.h" |
1951 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1952 | | #include "stub/i386-bsd.elf-fold.h" |
1953 | | |
1954 | | void |
1955 | | PackBSDElf32x86::buildLoader(const Filter *ft) |
1956 | 0 | { |
1957 | 0 | unsigned char tmp[sizeof(stub_i386_bsd_elf_fold)]; |
1958 | 0 | memcpy(tmp, stub_i386_bsd_elf_fold, sizeof(stub_i386_bsd_elf_fold)); |
1959 | 0 | checkPatch(nullptr, 0, 0, 0); // reset |
1960 | 0 | if (opt->o_unix.is_ptinterp) { |
1961 | 0 | unsigned j; |
1962 | 0 | for (j = 0; j < sizeof(stub_i386_bsd_elf_fold)-1; ++j) { |
1963 | 0 | if (0x60==tmp[ j] |
1964 | 0 | && 0x47==tmp[1+j] ) { |
1965 | | /* put INC EDI before PUSHA: inhibits auxv_up for PT_INTERP */ |
1966 | 0 | tmp[ j] = 0x47; |
1967 | 0 | tmp[1+j] = 0x60; |
1968 | 0 | break; |
1969 | 0 | } |
1970 | 0 | } |
1971 | 0 | } |
1972 | 0 | buildLinuxLoader( |
1973 | 0 | stub_i386_bsd_elf_entry, sizeof(stub_i386_bsd_elf_entry), |
1974 | 0 | tmp, sizeof(stub_i386_bsd_elf_fold), ft); |
1975 | 0 | } |
1976 | | |
1977 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1978 | | #include "stub/i386-netbsd.elf-entry.h" |
1979 | | |
1980 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
1981 | | #include "stub/i386-netbsd.elf-fold.h" |
1982 | | |
1983 | | #define WANT_NHDR_ENUM |
1984 | | #include "p_elf_enum.h" |
1985 | | #undef WANT_NHDR_ENUM |
1986 | | |
1987 | | void |
1988 | | PackNetBSDElf32x86::buildLoader(const Filter *ft) |
1989 | 0 | { |
1990 | 0 | unsigned char tmp[sizeof(stub_i386_netbsd_elf_fold)]; |
1991 | 0 | memcpy(tmp, stub_i386_netbsd_elf_fold, sizeof(stub_i386_netbsd_elf_fold)); |
1992 | 0 | checkPatch(nullptr, 0, 0, 0); // reset |
1993 | 0 | if (opt->o_unix.is_ptinterp) { |
1994 | 0 | unsigned j; |
1995 | 0 | for (j = 0; j < sizeof(stub_i386_netbsd_elf_fold)-1; ++j) { |
1996 | 0 | if (0x60==tmp[ j] |
1997 | 0 | && 0x47==tmp[1+j] ) { |
1998 | | /* put INC EDI before PUSHA: inhibits auxv_up for PT_INTERP */ |
1999 | 0 | tmp[ j] = 0x47; |
2000 | 0 | tmp[1+j] = 0x60; |
2001 | 0 | break; |
2002 | 0 | } |
2003 | 0 | } |
2004 | 0 | } |
2005 | 0 | buildLinuxLoader( |
2006 | 0 | stub_i386_netbsd_elf_entry, sizeof(stub_i386_netbsd_elf_entry), |
2007 | 0 | tmp, sizeof(stub_i386_netbsd_elf_fold), ft); |
2008 | 0 | } |
2009 | | |
2010 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2011 | | #include "stub/i386-openbsd.elf-fold.h" |
2012 | | |
2013 | | void |
2014 | | PackOpenBSDElf32x86::buildLoader(const Filter *ft) |
2015 | 0 | { |
2016 | 0 | unsigned char tmp[sizeof(stub_i386_openbsd_elf_fold)]; |
2017 | 0 | memcpy(tmp, stub_i386_openbsd_elf_fold, sizeof(stub_i386_openbsd_elf_fold)); |
2018 | 0 | checkPatch(nullptr, 0, 0, 0); // reset |
2019 | 0 | if (opt->o_unix.is_ptinterp) { |
2020 | 0 | unsigned j; |
2021 | 0 | for (j = 0; j < sizeof(stub_i386_openbsd_elf_fold)-1; ++j) { |
2022 | 0 | if (0x60==tmp[ j] |
2023 | 0 | && 0x47==tmp[1+j] ) { |
2024 | | /* put INC EDI before PUSHA: inhibits auxv_up for PT_INTERP */ |
2025 | 0 | tmp[ j] = 0x47; |
2026 | 0 | tmp[1+j] = 0x60; |
2027 | 0 | break; |
2028 | 0 | } |
2029 | 0 | } |
2030 | 0 | } |
2031 | 0 | buildLinuxLoader( |
2032 | 0 | stub_i386_bsd_elf_entry, sizeof(stub_i386_bsd_elf_entry), |
2033 | 0 | tmp, sizeof(stub_i386_openbsd_elf_fold), ft); |
2034 | 0 | } |
2035 | | |
2036 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2037 | | #include "stub/arm.v5a-linux.elf-entry.h" |
2038 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2039 | | #include "stub/arm.v5a-linux.elf-so_entry.h" |
2040 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2041 | | #include "stub/arm.v5a-linux.elf-fold.h" |
2042 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2043 | | #include "stub/arm.v5a-linux.elf-so_fold.h" |
2044 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2045 | | #include "stub/arm.v5t-linux.shlib-init.h" |
2046 | | |
2047 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2048 | | #include "stub/arm.v4a-linux.elf-entry.h" |
2049 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2050 | | #include "stub/arm.v4a-linux.elf-so_entry.h" |
2051 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2052 | | #include "stub/arm.v4a-linux.elf-fold.h" |
2053 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2054 | | #include "stub/arm.v4a-linux.elf-so_fold.h" |
2055 | | #if 0 |
2056 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2057 | | #include "stub/arm.v4a-linux.shlib-init.h" |
2058 | | #endif |
2059 | | |
2060 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2061 | | #include "stub/armeb.v4a-linux.elf-entry.h" |
2062 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2063 | | #include "stub/armeb.v4a-linux.elf-fold.h" |
2064 | | |
2065 | | void |
2066 | | PackLinuxElf32armBe::buildLoader(Filter const *ft) |
2067 | 0 | { |
2068 | 0 | buildLinuxLoader( |
2069 | 0 | stub_armeb_v4a_linux_elf_entry, sizeof(stub_armeb_v4a_linux_elf_entry), |
2070 | 0 | stub_armeb_v4a_linux_elf_fold, sizeof(stub_armeb_v4a_linux_elf_fold), ft); |
2071 | 0 | } |
2072 | | |
2073 | | void |
2074 | | PackLinuxElf32armLe::buildLoader(Filter const *ft) |
2075 | 0 | { |
2076 | 0 | if (Elf32_Ehdr::ELFOSABI_LINUX==ei_osabi) { |
2077 | 0 | if (0!=xct_off) { // shared library |
2078 | 0 | buildLinuxLoader( // FIXME: 4 vs 5 ? |
2079 | 0 | stub_arm_v5a_linux_elf_so_entry, sizeof(stub_arm_v5a_linux_elf_so_entry), |
2080 | 0 | stub_arm_v5a_linux_elf_so_fold, sizeof(stub_arm_v5a_linux_elf_so_fold), ft); |
2081 | 0 | return; |
2082 | 0 | } |
2083 | 0 | buildLinuxLoader( |
2084 | 0 | stub_arm_v5a_linux_elf_entry, sizeof(stub_arm_v5a_linux_elf_entry), |
2085 | 0 | stub_arm_v5a_linux_elf_fold, sizeof(stub_arm_v5a_linux_elf_fold), ft); |
2086 | 0 | } |
2087 | 0 | else { |
2088 | 0 | buildLinuxLoader( |
2089 | 0 | stub_arm_v4a_linux_elf_entry, sizeof(stub_arm_v4a_linux_elf_entry), |
2090 | 0 | stub_arm_v4a_linux_elf_fold, sizeof(stub_arm_v4a_linux_elf_fold), ft); |
2091 | 0 | } |
2092 | 0 | } |
2093 | | |
2094 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2095 | | #include "stub/mipsel.r3000-linux.elf-entry.h" |
2096 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2097 | | #include "stub/mipsel.r3000-linux.elf-fold.h" |
2098 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2099 | | #include "stub/mipsel.r3000-linux.shlib-init.h" |
2100 | | |
2101 | | void |
2102 | | PackLinuxElf32mipsel::buildLoader(Filter const *ft) |
2103 | 0 | { |
2104 | 0 | if (0!=xct_off) { // shared library |
2105 | 0 | buildLinuxLoader( |
2106 | 0 | stub_mipsel_r3000_linux_shlib_init, sizeof(stub_mipsel_r3000_linux_shlib_init), |
2107 | 0 | nullptr, 0, ft ); |
2108 | 0 | return; |
2109 | 0 | } |
2110 | 0 | buildLinuxLoader( |
2111 | 0 | stub_mipsel_r3000_linux_elf_entry, sizeof(stub_mipsel_r3000_linux_elf_entry), |
2112 | 0 | stub_mipsel_r3000_linux_elf_fold, sizeof(stub_mipsel_r3000_linux_elf_fold), ft); |
2113 | 0 | } |
2114 | | |
2115 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2116 | | #include "stub/mips.r3000-linux.elf-entry.h" |
2117 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2118 | | #include "stub/mips.r3000-linux.elf-fold.h" |
2119 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2120 | | #include "stub/mips.r3000-linux.shlib-init.h" |
2121 | | |
2122 | | void |
2123 | | PackLinuxElf32mipseb::buildLoader(Filter const *ft) |
2124 | 0 | { |
2125 | 0 | if (0!=xct_off) { // shared library |
2126 | 0 | buildLinuxLoader( |
2127 | 0 | stub_mips_r3000_linux_shlib_init, sizeof(stub_mips_r3000_linux_shlib_init), |
2128 | 0 | nullptr, 0, ft ); |
2129 | 0 | return; |
2130 | 0 | } |
2131 | 0 | buildLinuxLoader( |
2132 | 0 | stub_mips_r3000_linux_elf_entry, sizeof(stub_mips_r3000_linux_elf_entry), |
2133 | 0 | stub_mips_r3000_linux_elf_fold, sizeof(stub_mips_r3000_linux_elf_fold), ft); |
2134 | 0 | } |
2135 | | |
2136 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2137 | | #include "stub/powerpc-linux.elf-entry.h" |
2138 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2139 | | #include "stub/powerpc-linux.elf-fold.h" |
2140 | | |
2141 | | void |
2142 | | PackLinuxElf32ppc::buildLoader(const Filter *ft) |
2143 | 0 | { |
2144 | 0 | buildLinuxLoader( |
2145 | 0 | stub_powerpc_linux_elf_entry, sizeof(stub_powerpc_linux_elf_entry), |
2146 | 0 | stub_powerpc_linux_elf_fold, sizeof(stub_powerpc_linux_elf_fold), ft); |
2147 | 0 | } |
2148 | | |
2149 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2150 | | #include "stub/powerpc64le-linux.elf-entry.h" |
2151 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2152 | | #include "stub/powerpc64le-linux.elf-fold.h" |
2153 | | |
2154 | | void |
2155 | | PackLinuxElf64ppcle::buildLoader(const Filter *ft) |
2156 | 0 | { |
2157 | 0 | buildLinuxLoader( |
2158 | 0 | stub_powerpc64le_linux_elf_entry, sizeof(stub_powerpc64le_linux_elf_entry), |
2159 | 0 | stub_powerpc64le_linux_elf_fold, sizeof(stub_powerpc64le_linux_elf_fold), ft); |
2160 | 0 | } |
2161 | | |
2162 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2163 | | #include "stub/powerpc64-linux.elf-entry.h" |
2164 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2165 | | #include "stub/powerpc64-linux.elf-fold.h" |
2166 | | |
2167 | | void |
2168 | | PackLinuxElf64ppc::buildLoader(const Filter *ft) |
2169 | 0 | { |
2170 | 0 | buildLinuxLoader( |
2171 | 0 | stub_powerpc64_linux_elf_entry, sizeof(stub_powerpc64_linux_elf_entry), |
2172 | 0 | stub_powerpc64_linux_elf_fold, sizeof(stub_powerpc64_linux_elf_fold), ft); |
2173 | 0 | } |
2174 | | |
2175 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2176 | | #include "stub/amd64-linux.elf-entry.h" |
2177 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2178 | | #include "stub/amd64-linux.elf-fold.h" |
2179 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2180 | | #include "stub/amd64-linux.elf-so_entry.h" |
2181 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2182 | | #include "stub/amd64-linux.elf-so_fold.h" |
2183 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2184 | | #include "stub/amd64-linux.shlib-init.h" |
2185 | | |
2186 | | void |
2187 | | PackLinuxElf64amd::buildLoader(const Filter *ft) |
2188 | 0 | { |
2189 | 0 | if (0!=xct_off) { // shared library |
2190 | 0 | buildLinuxLoader( |
2191 | 0 | stub_amd64_linux_elf_so_entry, sizeof(stub_amd64_linux_elf_so_entry), |
2192 | 0 | stub_amd64_linux_elf_so_fold, sizeof(stub_amd64_linux_elf_so_fold), ft); |
2193 | 0 | return; |
2194 | 0 | } |
2195 | 0 | buildLinuxLoader( |
2196 | 0 | stub_amd64_linux_elf_entry, sizeof(stub_amd64_linux_elf_entry), |
2197 | 0 | stub_amd64_linux_elf_fold, sizeof(stub_amd64_linux_elf_fold), ft); |
2198 | 0 | } |
2199 | | |
2200 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2201 | | #include "stub/arm64-linux.elf-entry.h" |
2202 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2203 | | #include "stub/arm64-linux.elf-so_entry.h" |
2204 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2205 | | #include "stub/arm64-linux.elf-fold.h" |
2206 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2207 | | #include "stub/arm64-linux.elf-so_fold.h" |
2208 | | static const CLANG_FORMAT_DUMMY_STATEMENT |
2209 | | #include "stub/arm64-linux.shlib-init.h" |
2210 | | |
2211 | | void |
2212 | | PackLinuxElf64arm::buildLoader(const Filter *ft) |
2213 | 0 | { |
2214 | 0 | if (0!=xct_off) { // shared library |
2215 | 0 | buildLinuxLoader( |
2216 | 0 | stub_arm64_linux_elf_so_entry, sizeof(stub_arm64_linux_elf_so_entry), |
2217 | 0 | stub_arm64_linux_elf_so_fold, sizeof(stub_arm64_linux_elf_so_fold), ft); |
2218 | 0 | return; |
2219 | 0 | } |
2220 | 0 | buildLinuxLoader( |
2221 | 0 | stub_arm64_linux_elf_entry, sizeof(stub_arm64_linux_elf_entry), |
2222 | 0 | stub_arm64_linux_elf_fold, sizeof(stub_arm64_linux_elf_fold), ft); |
2223 | 0 | } |
2224 | | |
2225 | | // DT_HASH, DT_GNU_HASH have no explicit length (except in ElfXX_Shdr), |
2226 | | // so it is hard to detect when the index of a hash chain is out-of-bounds. |
2227 | | // Workaround: Assume no overlap of DT_* tables (and often contiguous.) |
2228 | | // Then any given table ends at least as early as when another table begins. |
2229 | | // So find the tables, and sort the offsets. |
2230 | | // The 32-bit DT_xxxxx keys have the same values as 64-bit DT_xxxxx keys. |
2231 | | static unsigned const dt_keys[] = { |
2232 | | Elf64_Dyn::DT_SYMTAB, |
2233 | | Elf64_Dyn::DT_VERSYM, // not small integer |
2234 | | Elf64_Dyn::DT_VERNEED, // not small integer |
2235 | | Elf64_Dyn::DT_HASH, |
2236 | | Elf64_Dyn::DT_GNU_HASH, // not small integer |
2237 | | Elf64_Dyn::DT_STRTAB, |
2238 | | Elf64_Dyn::DT_VERDEF, // not small integer |
2239 | | Elf64_Dyn::DT_REL, |
2240 | | Elf64_Dyn::DT_RELA, |
2241 | | Elf64_Dyn::DT_FINI_ARRAY, |
2242 | | Elf64_Dyn::DT_INIT_ARRAY, |
2243 | | Elf64_Dyn::DT_PREINIT_ARRAY, |
2244 | | 0, |
2245 | | }; |
2246 | | |
2247 | | static int __acc_cdecl_qsort |
2248 | | qcmp_unsigned(void const *const aa, void const *const bb) |
2249 | 37.9k | { |
2250 | 37.9k | unsigned a = *(unsigned const *)aa; |
2251 | 37.9k | unsigned b = *(unsigned const *)bb; |
2252 | 37.9k | if (a < b) return -1; |
2253 | 9.91k | if (a > b) return 1; |
2254 | 88 | return 0; |
2255 | 9.91k | } |
2256 | | |
2257 | | void |
2258 | | PackLinuxElf32::sort_DT32_offsets(Elf32_Dyn const *const dynp0) |
2259 | 3.35k | { |
2260 | 3.35k | mb_dt_offsets.alloc(sizeof(unsigned) * sizeof(dt_keys)/sizeof(dt_keys[0])); |
2261 | 3.35k | mb_dt_offsets.clear(); |
2262 | 3.35k | dt_offsets = (unsigned *)mb_dt_offsets.getVoidPtr(); |
2263 | 3.35k | unsigned n_off = 0, k; |
2264 | 41.9k | for (unsigned j=0; ((k = dt_keys[j]), k); ++j) { |
2265 | 38.8k | dt_offsets[n_off] = 0; // default to "not found" |
2266 | 38.8k | u32_t rva = 0; |
2267 | 38.8k | if (k < DT_NUM) { // in range of easy table |
2268 | 25.7k | if (!dt_table[k]) { |
2269 | 14.7k | continue; // not present in input |
2270 | 14.7k | } |
2271 | 11.0k | rva = get_te32(&dynp0[-1+ dt_table[k]].d_val); |
2272 | 11.0k | } |
2273 | 13.0k | else if (file_image) { // why is this guard necessary? |
2274 | 13.0k | rva = elf_unsigned_dynamic(k); // zero if not found |
2275 | 13.0k | } |
2276 | 24.1k | if (!rva) { |
2277 | 10.8k | continue; // not present in input |
2278 | 10.8k | } |
2279 | 13.2k | Elf32_Phdr const *phdr = elf_find_Phdr_for_va(rva, phdri, e_phnum); |
2280 | 13.2k | if (!phdr) { |
2281 | 171 | char msg[60]; snprintf(msg, sizeof(msg), "bad DT_{%#x} = %#x (no Phdr)", |
2282 | 171 | k, rva); |
2283 | 171 | throwCantPack(msg); |
2284 | 171 | } |
2285 | 13.0k | dt_offsets[n_off] = (rva - get_te32(&phdr->p_vaddr)) + get_te32(&phdr->p_offset); |
2286 | | |
2287 | 13.0k | if (file_size <= dt_offsets[n_off]) { |
2288 | 42 | char msg[60]; snprintf(msg, sizeof(msg), "bad DT_{%#x} = %#x (beyond EOF)", |
2289 | 42 | k, dt_offsets[n_off]); |
2290 | 42 | throwCantPack(msg); |
2291 | 42 | } |
2292 | 13.0k | n_off += !!dt_offsets[n_off]; |
2293 | 13.0k | } |
2294 | 3.13k | dt_offsets[n_off++] = file_size; // sentinel |
2295 | 3.13k | upx_qsort(dt_offsets, n_off, sizeof(dt_offsets[0]), qcmp_unsigned); |
2296 | 3.13k | } |
2297 | | |
2298 | | unsigned PackLinuxElf32::find_dt_ndx(unsigned rva) |
2299 | 6.00k | { |
2300 | 6.00k | unsigned *const dto = (unsigned *)mb_dt_offsets.getVoidPtr(); |
2301 | 6.00k | unsigned const dto_size = mb_dt_offsets.getSize() / sizeof(*dto); |
2302 | 12.8k | for (unsigned j = 0; j < dto_size && dto[j]; ++j) { // linear search of short table |
2303 | 12.6k | if (rva == dto[j]) { |
2304 | 5.85k | return j; |
2305 | 5.85k | } |
2306 | 12.6k | } |
2307 | 150 | return ~0u; |
2308 | 6.00k | } |
2309 | | |
2310 | | unsigned PackLinuxElf32::elf_find_table_size(unsigned dt_type, unsigned sh_type) |
2311 | 6.44k | { |
2312 | 6.44k | Elf32_Shdr const *sec = elf_find_section_type(sh_type); |
2313 | 6.44k | if (sec) { // Cheat the easy way: use _Shdr. (No _Shdr anyway for de-compression) |
2314 | 0 | return get_te32(&sec->sh_size); |
2315 | 0 | } |
2316 | | // Honest hard work: use _Phdr |
2317 | 6.44k | unsigned x_rva; |
2318 | 6.44k | if (dt_type < DT_NUM) { |
2319 | 4.74k | unsigned const x_ndx = dt_table[dt_type]; |
2320 | 4.74k | if (!x_ndx) { // no such entry |
2321 | 381 | return 0; |
2322 | 381 | } |
2323 | 4.36k | x_rva = get_te32(&dynseg[-1+ x_ndx].d_val); |
2324 | 4.36k | } |
2325 | 1.69k | else { |
2326 | 1.69k | x_rva = elf_unsigned_dynamic(dt_type); |
2327 | 1.69k | } |
2328 | 6.06k | Elf32_Phdr const *const x_phdr = elf_find_Phdr_for_va(x_rva, phdri, e_phnum); |
2329 | 6.06k | if (!x_phdr) |
2330 | 60 | return ~0u; // corrupted Phdrs? |
2331 | 6.00k | unsigned const d_off = x_rva - get_te32(&x_phdr->p_vaddr); |
2332 | 6.00k | unsigned const y_ndx = find_dt_ndx(d_off + get_te32(&x_phdr->p_offset)); |
2333 | 6.00k | if (~0u != y_ndx) { |
2334 | 5.85k | return dt_offsets[1+ y_ndx] - dt_offsets[y_ndx]; |
2335 | 5.85k | } |
2336 | 150 | return ~0u; |
2337 | 6.00k | } |
2338 | | |
2339 | | void |
2340 | | PackLinuxElf32::invert_pt_dynamic(Elf32_Dyn const *dynp, u32_t headway) |
2341 | 3.97k | { |
2342 | 3.97k | if (dt_table[Elf32_Dyn::DT_NULL]) { |
2343 | 553 | return; // not 1st time; do not change upx_dt_init |
2344 | 553 | } |
2345 | 3.41k | Elf32_Dyn const *const dynp0 = dynp; |
2346 | 3.41k | unsigned ndx = 0; |
2347 | 3.41k | unsigned const limit = headway / sizeof(*dynp); |
2348 | 3.41k | if (dynp) |
2349 | 210k | for (; ; ++ndx, ++dynp) { |
2350 | 210k | if (limit <= ndx) { |
2351 | 41 | throwCantPack("DT_NULL not found"); |
2352 | 41 | } |
2353 | 210k | u32_t const d_tag = get_te32(&dynp->d_tag); |
2354 | 210k | if (d_tag < DT_NUM) { |
2355 | 36.2k | if (Elf32_Dyn::DT_NEEDED != d_tag |
2356 | 33.9k | && dt_table[d_tag] |
2357 | 797 | && get_te32(&dynp->d_val) |
2358 | 797 | != get_te32(&dynp0[-1+ dt_table[d_tag]].d_val)) { |
2359 | 24 | throwCantPack("duplicate DT_%#x: [%#x] [%#x]", |
2360 | 24 | (unsigned)d_tag, -1+ dt_table[d_tag], ndx); |
2361 | 24 | } |
2362 | 36.2k | dt_table[d_tag] = 1+ ndx; |
2363 | 36.2k | } |
2364 | 210k | if (Elf32_Dyn::DT_NULL == d_tag) { |
2365 | 3.35k | break; // check here so that dt_table[DT_NULL] is set |
2366 | 3.35k | } |
2367 | 210k | } |
2368 | 3.35k | sort_DT32_offsets(dynp0); |
2369 | | |
2370 | 3.35k | upx_dt_init = 0; |
2371 | 3.35k | if (dt_table[Elf32_Dyn::DT_INIT]) upx_dt_init = Elf32_Dyn::DT_INIT; |
2372 | 2.22k | else if (dt_table[Elf32_Dyn::DT_PREINIT_ARRAY]) upx_dt_init = Elf32_Dyn::DT_PREINIT_ARRAY; |
2373 | 2.17k | else if (dt_table[Elf32_Dyn::DT_INIT_ARRAY]) upx_dt_init = Elf32_Dyn::DT_INIT_ARRAY; |
2374 | | |
2375 | 3.35k | unsigned const z_str = dt_table[Elf32_Dyn::DT_STRSZ]; |
2376 | 3.35k | strtab_max = !z_str ? 0 : get_te32(&dynp0[-1+ z_str].d_val); |
2377 | 3.35k | unsigned const z_tab = dt_table[Elf32_Dyn::DT_STRTAB]; |
2378 | 3.35k | unsigned const tmp1 = !z_tab ? 0 : get_te32(&dynp0[-1+ z_tab].d_val); |
2379 | 3.35k | if (tmp1 < sz_elf_hdrs) { |
2380 | 118 | throwCantPack("bad DT_STRTAB %#x", tmp1); |
2381 | 118 | } |
2382 | 3.23k | unsigned const strtab_beg = !z_tab ? 0 : elf_get_offset_from_address(tmp1); |
2383 | | |
2384 | 3.23k | if (!z_str || !z_tab || !(strtab_max + strtab_beg) |
2385 | 3.00k | || (this->file_size - strtab_beg) < strtab_max // strtab overlaps EOF |
2386 | | // last string in table must have terminating NUL |
2387 | 2.92k | || '\0' != ((char *)file_image.getVoidPtr())[-1+ strtab_max + strtab_beg] |
2388 | 3.23k | ) { |
2389 | 103 | throwCantPack("bad DT_STRSZ %#x", strtab_max); |
2390 | 103 | } |
2391 | | |
2392 | 3.13k | { // Find end of DT_SYMTAB |
2393 | 3.13k | unsigned const tmp2 = elf_find_table_size(Elf32_Dyn::DT_SYMTAB, |
2394 | 3.13k | Elf32_Shdr::SHT_DYNSYM); |
2395 | 3.13k | symnum_max = (~0u == tmp2) ? 0 : tmp2 / sizeof(Elf32_Sym); |
2396 | 3.13k | } |
2397 | | |
2398 | 3.13k | unsigned v_sym = dt_table[Elf32_Dyn::DT_SYMTAB]; |
2399 | 3.13k | if (v_sym) { |
2400 | 2.52k | v_sym = elf_get_offset_from_address(get_te32(&dynp0[-1+ v_sym].d_val)); |
2401 | 2.52k | } |
2402 | 3.13k | unsigned v_hsh = dt_table[Elf32_Dyn::DT_HASH]; |
2403 | 3.13k | if (v_hsh) { |
2404 | 1.99k | v_hsh = elf_get_offset_from_address(get_te32(&dynp0[-1+ v_hsh].d_val)); |
2405 | 1.99k | } |
2406 | 3.13k | if (v_hsh && file_image) { |
2407 | 1.88k | hashtab = (unsigned const *)elf_find_dynamic(Elf32_Dyn::DT_HASH); |
2408 | 1.88k | if (!hashtab) { |
2409 | 45 | throwCantPack("bad DT_HASH %#x", v_hsh); |
2410 | 45 | } |
2411 | | // Find end of DT_HASH |
2412 | 1.83k | hashend = (unsigned const *)(void const *)(elf_find_table_size( |
2413 | 1.83k | Elf32_Dyn::DT_HASH, Elf32_Shdr::SHT_HASH) + (char const *)hashtab); |
2414 | 1.83k | if (!hashtab || (char const *)hashend <= (char const *)&hashtab[2] |
2415 | 1.82k | || file_image.getSizeInBytes() |
2416 | 1.82k | < (unsigned)((char const *)&hashtab[2] - (char *)&file_image[0]) ) |
2417 | 11 | { |
2418 | 11 | throwCantPack("bad DT_HASH %#x", v_hsh); |
2419 | 11 | } |
2420 | | |
2421 | 1.82k | unsigned const nbucket = get_te32(&hashtab[0]); |
2422 | 1.82k | unsigned const *const buckets = &hashtab[2]; |
2423 | 1.82k | unsigned const *const chains = &buckets[nbucket]; (void)chains; |
2424 | 1.82k | if ((unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image)) |
2425 | 1.82k | <= sizeof(unsigned)*nbucket ) { |
2426 | 55 | throwCantPack("bad nbucket %#x\n", nbucket); |
2427 | 55 | } |
2428 | | |
2429 | 1.77k | if ((unsigned)(hashend - buckets) < nbucket |
2430 | 1.75k | || !v_sym || (unsigned)file_size <= v_sym |
2431 | 1.72k | || ((v_hsh < v_sym) && (v_sym - v_hsh) < sizeof(*buckets)*(2+ nbucket)) |
2432 | 1.77k | ) { |
2433 | 63 | throwCantPack("bad DT_HASH nbucket=%#x len=%#x", |
2434 | 63 | nbucket, (v_sym - v_hsh)); |
2435 | 63 | } |
2436 | 1.70k | unsigned chmax = 0; |
2437 | 1.04M | for (unsigned j= 0; j < nbucket; ++j) { |
2438 | 1.04M | unsigned x = get_te32(&buckets[j]); |
2439 | 1.04M | if (chmax < x) { |
2440 | 6.80k | chmax = x; |
2441 | 6.80k | } |
2442 | 1.04M | } |
2443 | 1.70k | if ((v_hsh < v_sym) && (v_sym - v_hsh) < |
2444 | 1.33k | (sizeof(*buckets)*(2+ nbucket) + sizeof(*chains)*(1+ chmax))) { |
2445 | 89 | throwCantPack("bad DT_HASH nbucket=%#x len=%#x", |
2446 | 89 | nbucket, (v_sym - v_hsh)); |
2447 | 89 | } |
2448 | 1.70k | } |
2449 | 2.86k | unsigned const v_gsh = elf_unsigned_dynamic(Elf32_Dyn::DT_GNU_HASH); |
2450 | 2.86k | if (v_gsh && file_image) { |
2451 | | // Not similar to DT_HASH because DT_GNU_HASH is not small (0x6ffffef5). |
2452 | 1.69k | gashtab = (unsigned const *)elf_find_dynamic(Elf32_Dyn::DT_GNU_HASH); |
2453 | 1.69k | gashend = (unsigned const *)(void const *)(elf_find_table_size( |
2454 | 1.69k | Elf32_Dyn::DT_GNU_HASH, Elf32_Shdr::SHT_GNU_HASH) + (char const *)gashtab); |
2455 | 1.69k | if (!gashtab || (char const *)gashend <= (char const *)&gashtab[4] |
2456 | 1.68k | || file_image.getSizeInBytes() |
2457 | 1.68k | < (unsigned)((char const *)&gashtab[4] - (char *)&file_image[0]) ) |
2458 | 15 | { |
2459 | 15 | throwCantPack("bad DT_GNU_HASH %#x", v_gsh); |
2460 | 15 | } |
2461 | | |
2462 | 1.68k | unsigned const n_bucket = get_te32(&gashtab[0]); |
2463 | 1.68k | unsigned const symbias = get_te32(&gashtab[1]); |
2464 | 1.68k | unsigned const n_bitmask = get_te32(&gashtab[2]); |
2465 | 1.68k | unsigned const gnu_shift = get_te32(&gashtab[3]); |
2466 | 1.68k | u32_t const *const bitmask = (u32_t const *)(void const *)&gashtab[4]; |
2467 | 1.68k | unsigned const *const buckets = (unsigned const *)&bitmask[n_bitmask]; |
2468 | 1.68k | unsigned const *const hasharr = &buckets[n_bucket]; (void)hasharr; |
2469 | 1.68k | if (!n_bucket || (1u<<31) <= n_bucket /* fie on fuzzers */ |
2470 | 1.62k | || (unsigned)(gashend - buckets) < n_bucket |
2471 | 1.61k | || (file_size + file_image) <= (void const *)hasharr) { |
2472 | 89 | throwCantPack("bad n_bucket %#x\n", n_bucket); |
2473 | 89 | } |
2474 | | // It would be better to detect zeroes shifted into low 5 bits of: |
2475 | | // (037 & (hash_32 >> gnu_shift)) |
2476 | | // but compilers can be stupid. |
2477 | 1.59k | if (31 < gnu_shift) { |
2478 | 61 | throwCantPack("bad gnu_shift %#x", gnu_shift); |
2479 | 61 | } |
2480 | | // unsigned const *const gashend = &hasharr[n_bucket]; |
2481 | | // minimum, except: |
2482 | | // Rust and Android trim unused zeroes from high end of hasharr[] |
2483 | 1.53k | unsigned bmax = 0; |
2484 | 269k | for (unsigned j= 0; j < n_bucket; ++j) { |
2485 | 267k | unsigned bj = get_te32(&buckets[j]); |
2486 | 267k | if (bj) { |
2487 | 149k | if (bj < symbias) { |
2488 | 22 | throwCantPack("bad DT_GNU_HASH bucket[%d] < symbias{%#x}\n", |
2489 | 22 | bj, symbias); |
2490 | 22 | } |
2491 | 149k | if (bmax < bj) { |
2492 | 6.92k | bmax = bj; |
2493 | 6.92k | } |
2494 | 149k | } |
2495 | 267k | } |
2496 | 1.50k | if (1==n_bucket && 0==buckets[0] |
2497 | 247 | && 1==n_bitmask && 0==bitmask[0]) { |
2498 | | // 2021-09-11 Rust on RaspberryPi apparently uses this to minimize space. |
2499 | | // But then the DT_GNU_HASH symbol lookup algorithm always fails? |
2500 | | // https://github.com/upx/upx/issues/525 |
2501 | 116 | } else |
2502 | 1.39k | if (bmax) { |
2503 | 1.21k | if ((1+ bmax) < symbias) { |
2504 | 14 | throwCantPack("bad DT_GNU_HASH (1+ max_bucket)=%#x < symbias=%#x", |
2505 | 14 | 1+ bmax, symbias); |
2506 | 14 | } |
2507 | 1.20k | bmax -= symbias; |
2508 | 1.20k | } |
2509 | | |
2510 | 1.49k | unsigned r = 0; |
2511 | 1.49k | if (!n_bucket || !n_bitmask || !v_sym |
2512 | 1.40k | || (r=1, ((-1+ n_bitmask) & n_bitmask)) // not a power of 2 |
2513 | 1.40k | || (r=2, (8*sizeof(u32_t) <= gnu_shift)) // shifted result always == 0 |
2514 | 1.40k | || (r=3, (n_bucket>>30)) // fie on fuzzers |
2515 | 1.40k | || (r=4, (n_bitmask>>30)) |
2516 | 1.40k | || (r=5, ((file_size/sizeof(unsigned)) |
2517 | 1.40k | <= ((sizeof(*bitmask)/sizeof(unsigned))*n_bitmask + 2*n_bucket))) // FIXME: weak |
2518 | 1.39k | || (r=6, ((v_gsh < v_sym) && (v_sym - v_gsh) < (sizeof(unsigned)*4 // headers |
2519 | 1.01k | + sizeof(*bitmask)*n_bitmask // bitmask |
2520 | 1.01k | + sizeof(*buckets)*n_bucket // buckets |
2521 | 1.01k | + sizeof(*hasharr)*(!bmax ? 0 : (1+ bmax)) // hasharr |
2522 | 1.01k | )) ) |
2523 | 1.49k | ) { |
2524 | 237 | char msg[90]; snprintf(msg, sizeof(msg), |
2525 | 237 | "bad DT_GNU_HASH n_bucket=%#x n_bitmask=%#x len=%#lx r=%d", |
2526 | 237 | n_bucket, n_bitmask, (long unsigned)(v_sym - v_gsh), r); |
2527 | 237 | throwCantPack(msg); |
2528 | 237 | } |
2529 | 1.49k | } |
2530 | 2.43k | e_shstrndx = get_te16(&ehdri.e_shstrndx); // who omitted this? |
2531 | 2.43k | if (e_shnum <= e_shstrndx |
2532 | 244 | && !(0==e_shnum && 0==e_shstrndx) ) { |
2533 | 37 | char msg[40]; snprintf(msg, sizeof(msg), |
2534 | 37 | "bad .e_shstrndx %d >= .e_shnum %d", e_shstrndx, e_shnum); |
2535 | 37 | throwCantPack(msg); |
2536 | 37 | } |
2537 | 2.43k | } |
2538 | | |
2539 | | Elf32_Phdr const * |
2540 | | PackLinuxElf32::elf_find_ptype(unsigned type, Elf32_Phdr const *phdr, unsigned phnum) |
2541 | 549 | { |
2542 | 83.2k | for (unsigned j = 0; j < phnum; ++j, ++phdr) { |
2543 | 82.8k | if (type == get_te32(&phdr->p_type)) { |
2544 | 158 | return phdr; |
2545 | 158 | } |
2546 | 82.8k | } |
2547 | 391 | return nullptr; |
2548 | 549 | } |
2549 | | |
2550 | | Elf64_Phdr const * |
2551 | | PackLinuxElf64::elf_find_ptype(unsigned type, Elf64_Phdr const *phdr, unsigned phnum) |
2552 | 571 | { |
2553 | 24.6k | for (unsigned j = 0; j < phnum; ++j, ++phdr) { |
2554 | 24.2k | if (type == get_te32(&phdr->p_type)) { |
2555 | 185 | return phdr; |
2556 | 185 | } |
2557 | 24.2k | } |
2558 | 386 | return nullptr; |
2559 | 571 | } |
2560 | | |
2561 | | Elf32_Shdr const *PackLinuxElf32::elf_find_section_name( |
2562 | | char const *const name |
2563 | | ) const |
2564 | 0 | { |
2565 | 0 | Elf32_Shdr const *shdr = shdri; |
2566 | 0 | if (!shdr) { |
2567 | 0 | return nullptr; |
2568 | 0 | } |
2569 | 0 | int j = e_shnum; |
2570 | 0 | for (; 0 <=--j; ++shdr) { |
2571 | 0 | unsigned const sh_name = get_te32(&shdr->sh_name); |
2572 | 0 | if ((u32_t)file_size <= sh_name) { // FIXME: weak |
2573 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
2574 | 0 | "bad Elf32_Shdr[%d].sh_name %#x", |
2575 | 0 | -1+ e_shnum -j, sh_name); |
2576 | 0 | throwCantPack(msg); |
2577 | 0 | } |
2578 | 0 | if (0==strcmp(name, &shstrtab[sh_name])) { |
2579 | 0 | return shdr; |
2580 | 0 | } |
2581 | 0 | } |
2582 | 0 | return nullptr; |
2583 | 0 | } |
2584 | | |
2585 | | Elf64_Shdr const *PackLinuxElf64::elf_find_section_name( |
2586 | | char const *const name |
2587 | | ) const |
2588 | 0 | { |
2589 | 0 | Elf64_Shdr const *shdr = shdri; |
2590 | 0 | if (!shdr) { |
2591 | 0 | return nullptr; |
2592 | 0 | } |
2593 | 0 | int j = e_shnum; |
2594 | 0 | for (; 0 <=--j; ++shdr) { |
2595 | 0 | unsigned const sh_name = get_te32(&shdr->sh_name); |
2596 | 0 | if ((u32_t)file_size <= sh_name) { // FIXME: weak |
2597 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
2598 | 0 | "bad Elf64_Shdr[%d].sh_name %#x", |
2599 | 0 | -1+ e_shnum -j, sh_name); |
2600 | 0 | throwCantPack(msg); |
2601 | 0 | } |
2602 | 0 | if (0==strcmp(name, &shstrtab[sh_name])) { |
2603 | 0 | return shdr; |
2604 | 0 | } |
2605 | 0 | } |
2606 | 0 | return nullptr; |
2607 | 0 | } |
2608 | | |
2609 | | Elf32_Shdr *PackLinuxElf32::elf_find_section_type( |
2610 | | unsigned const type |
2611 | | ) const |
2612 | 11.9k | { |
2613 | 11.9k | Elf32_Shdr *shdr = shdri; |
2614 | 11.9k | if (!shdr) { |
2615 | 11.9k | return nullptr; |
2616 | 11.9k | } |
2617 | 0 | int j = e_shnum; |
2618 | 0 | for (; 0 <=--j; ++shdr) { |
2619 | 0 | if (type==get_te32(&shdr->sh_type)) { |
2620 | 0 | return shdr; |
2621 | 0 | } |
2622 | 0 | } |
2623 | 0 | return nullptr; |
2624 | 0 | } |
2625 | | |
2626 | | Elf64_Shdr *PackLinuxElf64::elf_find_section_type( |
2627 | | unsigned const type |
2628 | | ) const |
2629 | 9.72k | { |
2630 | 9.72k | Elf64_Shdr *shdr = shdri; |
2631 | 9.72k | if (!shdr) { |
2632 | 9.72k | return nullptr; |
2633 | 9.72k | } |
2634 | 0 | int j = e_shnum; |
2635 | 0 | for (; 0 <=--j; ++shdr) { |
2636 | 0 | if (type==get_te32(&shdr->sh_type)) { |
2637 | 0 | return shdr; |
2638 | 0 | } |
2639 | 0 | } |
2640 | 0 | return nullptr; |
2641 | 0 | } |
2642 | | |
2643 | | char const *PackLinuxElf64::get_str_name(unsigned st_name, unsigned symnum) const |
2644 | 7.69k | { |
2645 | 7.69k | if (strtab_max <= st_name) { |
2646 | 30 | char msg[70]; snprintf(msg, sizeof(msg), |
2647 | 30 | "bad .st_name %#x in DT_SYMTAB[%d]", st_name, symnum); |
2648 | 30 | throwCantPack(msg); |
2649 | 30 | } |
2650 | 7.66k | return &dynstr[st_name]; |
2651 | 7.69k | } |
2652 | | |
2653 | | char const *PackLinuxElf64::get_dynsym_name(unsigned symnum, unsigned relnum) const |
2654 | 8.00k | { |
2655 | 8.00k | if (symnum_max <= symnum) { |
2656 | 311 | (void)relnum; |
2657 | 311 | return nullptr; |
2658 | 311 | } |
2659 | 7.69k | return get_str_name(get_te32(&dynsym[symnum].st_name), symnum); |
2660 | 8.00k | } |
2661 | | |
2662 | | bool PackLinuxElf64::calls_crt1(Elf64_Rela const *rela, int sz) |
2663 | 0 | { |
2664 | 0 | if (!dynsym || !dynstr || !rela) { |
2665 | 0 | return false; |
2666 | 0 | } |
2667 | 0 | for (unsigned relnum= 0; 0 < sz; (sz -= sizeof(Elf64_Rela)), ++rela, ++relnum) { |
2668 | 0 | unsigned const symnum = get_te64(&rela->r_info) >> 32; |
2669 | 0 | char const *const symnam = get_dynsym_name(symnum, relnum); |
2670 | 0 | if (0==strcmp(symnam, "__libc_start_main") // glibc |
2671 | 0 | || 0==strcmp(symnam, "__libc_init") // Android |
2672 | 0 | || 0==strcmp(symnam, "__uClibc_main") |
2673 | 0 | || 0==strcmp(symnam, "__uClibc_start_main")) |
2674 | 0 | return true; |
2675 | 0 | } |
2676 | 0 | return false; |
2677 | 0 | } |
2678 | | |
2679 | | char const *PackLinuxElf32::get_str_name(unsigned st_name, unsigned symnum) const |
2680 | 3.06k | { |
2681 | 3.06k | if (strtab_max <= st_name) { |
2682 | 54 | char msg[70]; snprintf(msg, sizeof(msg), |
2683 | 54 | "bad .st_name %#x in DT_SYMTAB[%d]\n", st_name, symnum); |
2684 | 54 | throwCantPack(msg); |
2685 | 54 | } |
2686 | 3.00k | return &dynstr[st_name]; |
2687 | 3.06k | } |
2688 | | |
2689 | | char const *PackLinuxElf32::get_dynsym_name(unsigned symnum, unsigned relnum) const |
2690 | 3.30k | { |
2691 | 3.30k | if (symnum_max <= symnum) { |
2692 | 239 | (void)relnum; |
2693 | 239 | return nullptr; |
2694 | 239 | } |
2695 | 3.06k | return get_str_name(get_te32(&dynsym[symnum].st_name), symnum); |
2696 | 3.30k | } |
2697 | | |
2698 | | bool PackLinuxElf32::calls_crt1(Elf32_Rel const *rel, int sz) |
2699 | 0 | { |
2700 | 0 | if (!dynsym || !dynstr || !rel) { |
2701 | 0 | return false; |
2702 | 0 | } |
2703 | 0 | for (unsigned relnum= 0; 0 < sz; (sz -= sizeof(Elf32_Rel)), ++rel, ++relnum) { |
2704 | 0 | unsigned const symnum = get_te32(&rel->r_info) >> 8; |
2705 | 0 | char const *const symnam = get_dynsym_name(symnum, relnum); |
2706 | 0 | if (0==strcmp(symnam, "__libc_start_main") // glibc |
2707 | 0 | || 0==strcmp(symnam, "__libc_init") // Android |
2708 | 0 | || 0==strcmp(symnam, "__uClibc_main") |
2709 | 0 | || 0==strcmp(symnam, "__uClibc_start_main")) |
2710 | 0 | return true; |
2711 | 0 | } |
2712 | 0 | return false; |
2713 | 0 | } |
2714 | | |
2715 | | tribool PackLinuxElf32::canUnpack() // bool, except -1: format known, but not packed |
2716 | 169k | { |
2717 | 169k | if (checkEhdr(&ehdri)) { |
2718 | 162k | return false; |
2719 | 162k | } |
2720 | 6.28k | if (get_te16(&ehdri.e_phnum) < 2) { |
2721 | 20 | throwCantUnpack("e_phnum must be >= 2"); |
2722 | 20 | } |
2723 | 6.26k | if (Elf32_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) { |
2724 | 786 | PackLinuxElf32help1(fi); |
2725 | 786 | } |
2726 | 6.26k | if (super::canUnpack()) { |
2727 | 800 | return true; |
2728 | 800 | } |
2729 | 5.46k | return false; |
2730 | 6.26k | } |
2731 | | |
2732 | | bool // false [often throwCantPack]: some defect; true: good so far |
2733 | | PackLinuxElf32::canPackOSABI(Elf32_Ehdr const *ehdr) |
2734 | 0 | { |
2735 | 0 | unsigned char osabi0 = ehdr->e_ident[Elf32_Ehdr::EI_OSABI]; |
2736 | | // The first PT_LOAD must cover the beginning of the file (0==p_offset). |
2737 | 0 | Elf32_Phdr const *phdr = phdri; |
2738 | 0 | note_size = 0; |
2739 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
2740 | 0 | if (j > ((MAX_ELF_HDR_32 - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))) { |
2741 | 0 | throwCantPack("too many ElfXX_Phdr; try '--force-execve'"); |
2742 | 0 | return false; |
2743 | 0 | } |
2744 | 0 | unsigned const p_type = get_te32(&phdr->p_type); |
2745 | 0 | unsigned const p_offset = get_te32(&phdr->p_offset); |
2746 | 0 | if (1!=exetype && PT_LOAD == p_type) { // 1st PT_LOAD |
2747 | 0 | exetype = 1; |
2748 | 0 | load_va = get_te32(&phdr->p_vaddr); // class data member |
2749 | | |
2750 | | // Cast on next line is to avoid a compiler bug (incorrect complaint) in |
2751 | | // Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64 |
2752 | | // error C4319: '~': zero extending 'unsigned int' to 'upx_uint64_t' of greater size |
2753 | 0 | unsigned const off = ~page_mask & (unsigned)load_va; |
2754 | |
|
2755 | 0 | if (off && off == p_offset) { // specific hint |
2756 | 0 | throwCantPack("Go-language PT_LOAD: try hemfix.c, or try '--force-execve'"); |
2757 | | // Fixing it inside upx fails because packExtent() reads original file. |
2758 | 0 | return false; |
2759 | 0 | } |
2760 | 0 | if (0 != p_offset) { // 1st PT_LOAD must cover Ehdr and Phdr |
2761 | 0 | throwCantPack("first PT_LOAD.p_offset != 0; try '--force-execve'"); |
2762 | 0 | return false; |
2763 | 0 | } |
2764 | 0 | hatch_off = ~3u & (3+ get_te32(&phdr->p_memsz)); |
2765 | 0 | } |
2766 | 0 | if (EM_MIPS == e_machine |
2767 | 0 | && (Elf32_Phdr::PT_MIPS_ABIFLAGS == p_type |
2768 | 0 | || Elf32_Phdr::PT_MIPS_REGINFO == p_type) |
2769 | 0 | ) { |
2770 | 0 | add_phdrx(phdr); // PT_MIPS_* |
2771 | 0 | unsigned mask = -1+ get_te32(&phdr->p_align); |
2772 | 0 | sz_phdrx = ~mask & (mask + sz_phdrx); |
2773 | 0 | sz_phdrx += get_te32(&phdr->p_memsz); |
2774 | |
|
2775 | 0 | } |
2776 | 0 | if (PT_NOTE32 == p_type) { |
2777 | 0 | if (osabi_note && Elf32_Ehdr::ELFOSABI_NONE==osabi0) { // Still seems to be generic. |
2778 | 0 | struct { |
2779 | 0 | struct Elf32_Nhdr nhdr; |
2780 | 0 | char name[8]; |
2781 | 0 | unsigned body; |
2782 | 0 | } note; |
2783 | 0 | memset(¬e, 0, sizeof(note)); |
2784 | 0 | fi->seek(p_offset, SEEK_SET); |
2785 | 0 | fi->readx(¬e, sizeof(note)); |
2786 | 0 | fi->seek(0, SEEK_SET); |
2787 | 0 | if (4==get_te32(¬e.nhdr.descsz) |
2788 | 0 | && 1==get_te32(¬e.nhdr.type) |
2789 | | // && 0==note.end |
2790 | 0 | && (1+ strlen(osabi_note))==get_te32(¬e.nhdr.namesz) |
2791 | 0 | && 0==strcmp(osabi_note, (char const *)¬e.name[0]) |
2792 | 0 | ) { |
2793 | 0 | osabi0 = ei_osabi; // Specified by PT_NOTE. |
2794 | 0 | } |
2795 | 0 | } |
2796 | 0 | } |
2797 | 0 | } |
2798 | 0 | if (Elf32_Ehdr::ELFOSABI_NONE ==osabi0 |
2799 | 0 | || Elf32_Ehdr::ELFOSABI_LINUX==osabi0) { // No EI_OSBAI, no PT_NOTE. |
2800 | 0 | unsigned const arm_eabi = 0xff000000u & get_te32(&ehdr->e_flags); |
2801 | 0 | if (Elf32_Ehdr::EM_ARM==e_machine |
2802 | 0 | && (EF_ARM_EABI_VER5==arm_eabi |
2803 | 0 | || EF_ARM_EABI_VER4==arm_eabi ) ) { |
2804 | | // armel-eabi armeb-eabi ARM Linux EABI version 4 is a mess. |
2805 | 0 | ei_osabi = osabi0 = Elf32_Ehdr::ELFOSABI_LINUX; |
2806 | 0 | } |
2807 | 0 | else { |
2808 | 0 | osabi0 = opt->o_unix.osabi0; // Possibly specified by command-line. |
2809 | 0 | } |
2810 | 0 | } |
2811 | 0 | if (osabi0!=ei_osabi) { |
2812 | 0 | return false; |
2813 | 0 | } |
2814 | 0 | return true; // good so far |
2815 | 0 | } |
2816 | | |
2817 | | #define WANT_SHDR_ENUM |
2818 | | #include "p_elf_enum.h" |
2819 | | #undef WANT_SHDR_ENUM |
2820 | | |
2821 | | upx_uint64_t PackLinuxElf32::canPack_Shdr(Elf32_Phdr const *pload_x0) |
2822 | 0 | { |
2823 | 0 | Elf32_Shdr const *shdr_xva = nullptr; |
2824 | 0 | Elf32_Shdr const *shdr = shdri; |
2825 | 0 | for (int j= e_shnum; --j>=0; ++shdr) { |
2826 | 0 | unsigned const sh_type = get_te32(&shdr->sh_type); |
2827 | 0 | if (!shdr_xva && Elf32_Shdr::SHF_EXECINSTR & get_te32(&shdr->sh_flags)) { |
2828 | 0 | shdr_xva = shdr; |
2829 | 0 | xct_va = get_te32(&shdr_xva->sh_addr); |
2830 | 0 | } |
2831 | | // Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY. |
2832 | 0 | if (!user_init_rp && ( |
2833 | 0 | ( Elf32_Dyn::DT_PREINIT_ARRAY==upx_dt_init |
2834 | 0 | && Elf32_Shdr::SHT_PREINIT_ARRAY==sh_type) |
2835 | 0 | || ( Elf32_Dyn::DT_INIT_ARRAY ==upx_dt_init |
2836 | 0 | && Elf32_Shdr::SHT_INIT_ARRAY ==sh_type) )) { |
2837 | 0 | unsigned user_init_ava = get_te32(&shdr->sh_addr); |
2838 | 0 | user_init_off = get_te32(&shdr->sh_offset); |
2839 | 0 | if ((u32_t)file_size <= user_init_off) { |
2840 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
2841 | 0 | "bad Elf32_Shdr[%d].sh_offset %#x", |
2842 | 0 | -1+ e_shnum - j, user_init_off); |
2843 | 0 | throwCantPack(msg); |
2844 | 0 | } |
2845 | | // Check that &file_image[user_init_off] has |
2846 | | // *_RELATIVE or *_ABS* relocation, and fetch user_init_va. |
2847 | | // If Elf32_Rela then the actual value is in Rela.r_addend. |
2848 | 0 | int z_rel = dt_table[Elf32_Dyn::DT_REL]; |
2849 | 0 | int z_rsz = dt_table[Elf32_Dyn::DT_RELSZ]; |
2850 | 0 | if (z_rel && z_rsz) { |
2851 | 0 | unsigned rel_off = get_te32(&dynseg[-1+ z_rel].d_val); |
2852 | 0 | if ((unsigned)file_size <= rel_off) { |
2853 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
2854 | 0 | "bad Elf32_Dynamic[DT_REL] %#x\n", |
2855 | 0 | rel_off); |
2856 | 0 | throwCantPack(msg); |
2857 | 0 | } |
2858 | 0 | Elf32_Rel *rp = (Elf32_Rel *)&file_image[rel_off]; |
2859 | 0 | unsigned relsz = get_te32(&dynseg[-1+ z_rsz].d_val); |
2860 | 0 | if ((unsigned)file_size <= relsz) { |
2861 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
2862 | 0 | "bad Elf32_Dynamic[DT_RELSZ] %#x\n", |
2863 | 0 | relsz); |
2864 | 0 | throwCantPack(msg); |
2865 | 0 | } |
2866 | 0 | Elf32_Rel *last = (Elf32_Rel *)(relsz + (char *)rp); |
2867 | 0 | for (; rp < last; ++rp) { |
2868 | 0 | unsigned r_va = get_te32(&rp->r_offset); |
2869 | 0 | if (r_va == user_init_ava) { // found the Elf32_Rel |
2870 | 0 | user_init_rp = rp; |
2871 | 0 | unsigned r_info = get_te32(&rp->r_info); |
2872 | 0 | unsigned r_type = ELF32_R_TYPE(r_info); |
2873 | 0 | set_te32(&dynsym[0].st_name, r_va); // for decompressor |
2874 | 0 | set_te32(&dynsym[0].st_value, r_info); |
2875 | 0 | if (Elf32_Ehdr::EM_ARM == e_machine) { |
2876 | 0 | if (R_ARM_RELATIVE == r_type) { |
2877 | 0 | user_init_va = get_te32(&file_image[user_init_off]); |
2878 | 0 | } |
2879 | 0 | else if (R_ARM_ABS32 == r_type) { |
2880 | 0 | unsigned symj = ELF32_R_SYM(r_info); |
2881 | 0 | user_init_va = get_te32(&dynsym[symj].st_value); |
2882 | 0 | set_te32(&rp->r_info, ELF32_R_INFO(0, R_ARM_RELATIVE)); |
2883 | | // pack3() will set &file_image[user_init_off] |
2884 | 0 | } |
2885 | 0 | else { |
2886 | 0 | goto bad; |
2887 | 0 | } |
2888 | 0 | } |
2889 | 0 | else if (Elf32_Ehdr::EM_386 == e_machine) { |
2890 | 0 | if (R_386_RELATIVE == r_type) { |
2891 | 0 | user_init_va = get_te32(&file_image[user_init_off]); |
2892 | 0 | } |
2893 | 0 | else if (R_386_32 == r_type) { |
2894 | 0 | unsigned symj = ELF32_R_SYM(r_info); |
2895 | 0 | user_init_va = get_te32(&dynsym[symj].st_value); |
2896 | 0 | set_te32(&rp->r_info, ELF32_R_INFO(0, R_386_RELATIVE)); |
2897 | | // pack3() will set &file_image[user_init_off] |
2898 | 0 | } |
2899 | 0 | else { |
2900 | 0 | goto bad; |
2901 | 0 | } |
2902 | 0 | } |
2903 | 0 | else { |
2904 | 0 | bad: |
2905 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
2906 | 0 | "bad relocation %#x DT_INIT_ARRAY[0]", |
2907 | 0 | r_info); |
2908 | 0 | throwCantPack(msg); |
2909 | 0 | } |
2910 | 0 | break; |
2911 | 0 | } |
2912 | 0 | } |
2913 | 0 | } |
2914 | 0 | unsigned const p_filesz = get_te32(&pload_x0->p_filesz); |
2915 | 0 | if (!((user_init_va - xct_va) < p_filesz)) { |
2916 | | // Not in executable portion of first executable PT_LOAD. |
2917 | 0 | if (0==user_init_va && is_asl) { |
2918 | | // Android allows (0 ==> skip) ? |
2919 | 0 | upx_dt_init = 0; // force steal of 'extra' DT_NULL |
2920 | | // XXX: FIXME: depends on SHT_DYNAMIC coming later |
2921 | 0 | } |
2922 | 0 | else { |
2923 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
2924 | 0 | "bad init address %#x in Elf32_Shdr[%d].%#x\n", |
2925 | 0 | (unsigned)user_init_va, -1+ e_shnum - j, user_init_off); |
2926 | 0 | throwCantPack(msg); |
2927 | 0 | } |
2928 | 0 | } |
2929 | 0 | } |
2930 | | // By default /usr/bin/ld leaves 4 extra DT_NULL to support pre-linking. |
2931 | | // Take one as a last resort. |
2932 | 0 | if ((Elf32_Dyn::DT_INIT==upx_dt_init || !upx_dt_init) |
2933 | 0 | && Elf32_Shdr::SHT_DYNAMIC == sh_type) { |
2934 | 0 | unsigned sh_offset = get_te32(&shdr->sh_offset); |
2935 | 0 | unsigned sh_size = get_te32(&shdr->sh_size); |
2936 | 0 | if ((unsigned)file_size < sh_size |
2937 | 0 | || (unsigned)file_size < sh_offset |
2938 | 0 | || ((unsigned)file_size - sh_offset) < sh_size) { |
2939 | 0 | throwCantPack("bad SHT_DYNAMIC"); |
2940 | 0 | } |
2941 | 0 | unsigned const n = get_te32(&shdr->sh_size) / sizeof(Elf32_Dyn); |
2942 | 0 | Elf32_Dyn *dynp = (Elf32_Dyn *)&file_image[get_te32(&shdr->sh_offset)]; |
2943 | 0 | for (; Elf32_Dyn::DT_NULL != dynp->d_tag; ++dynp) { |
2944 | 0 | if (upx_dt_init == get_te32(&dynp->d_tag)) { |
2945 | 0 | break; // re-found DT_INIT |
2946 | 0 | } |
2947 | 0 | } |
2948 | 0 | if ((1+ dynp) < (n+ dynseg)) { // not the terminator, so take it |
2949 | 0 | user_init_va = get_te32(&dynp->d_val); // 0 if (0==upx_dt_init) |
2950 | 0 | set_te32(&dynp->d_tag, upx_dt_init = Elf32_Dyn::DT_INIT); |
2951 | 0 | user_init_off = (char const *)&dynp->d_val - (char const *)&file_image[0]; |
2952 | 0 | } |
2953 | 0 | } |
2954 | 0 | } |
2955 | 0 | return xct_va; |
2956 | 0 | } |
2957 | | |
2958 | | upx_uint64_t PackLinuxElf64::canPack_Shdr(Elf64_Phdr const *pload_x0) |
2959 | 0 | { |
2960 | 0 | Elf64_Shdr const *shdr_xva = nullptr; |
2961 | 0 | Elf64_Shdr const *shdr = shdri; |
2962 | 0 | for (int j= e_shnum; --j>=0; ++shdr) { |
2963 | 0 | unsigned const sh_type = get_te32(&shdr->sh_type); |
2964 | 0 | if (!shdr_xva && Elf64_Shdr::SHF_EXECINSTR & get_te64(&shdr->sh_flags)) { |
2965 | 0 | shdr_xva = shdr; |
2966 | 0 | xct_va = get_te64_32(&shdr_xva->sh_addr); |
2967 | 0 | } |
2968 | | // Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY. |
2969 | 0 | if (!user_init_rp && ( |
2970 | 0 | ( Elf64_Dyn::DT_PREINIT_ARRAY==upx_dt_init |
2971 | 0 | && Elf64_Shdr::SHT_PREINIT_ARRAY==sh_type) |
2972 | 0 | || ( Elf64_Dyn::DT_INIT_ARRAY ==upx_dt_init |
2973 | 0 | && Elf64_Shdr::SHT_INIT_ARRAY ==sh_type) )) { |
2974 | 0 | unsigned user_init_ava = get_te64(&shdr->sh_addr); |
2975 | 0 | user_init_off = get_te64(&shdr->sh_offset); |
2976 | 0 | if ((u64_t)file_size <= user_init_off) { |
2977 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
2978 | 0 | "bad Elf64_Shdr[%d].sh_offset %#x", |
2979 | 0 | -1+ e_shnum - j, user_init_off); |
2980 | 0 | throwCantPack(msg); |
2981 | 0 | } |
2982 | | // Check that &file_image[user_init_off] has |
2983 | | // *_RELATIVE or *_ABS* relocation, and fetch user_init_va. |
2984 | | // If Elf_Rela then the actual value is in Rela.r_addend. |
2985 | 0 | int z_rel = dt_table[Elf64_Dyn::DT_RELA]; |
2986 | 0 | int z_rsz = dt_table[Elf64_Dyn::DT_RELASZ]; |
2987 | 0 | if (z_rel && z_rsz) { |
2988 | 0 | upx_uint64_t rel_off = get_te64(&dynseg[-1+ z_rel].d_val); |
2989 | 0 | if ((u64_t)file_size <= rel_off) { |
2990 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
2991 | 0 | "bad Elf64_Dynamic[DT_RELA] %#llx\n", |
2992 | 0 | rel_off); |
2993 | 0 | throwCantPack(msg); |
2994 | 0 | } |
2995 | 0 | Elf64_Rela *rp = (Elf64_Rela *)&file_image[rel_off]; |
2996 | 0 | upx_uint64_t relsz = get_te64(&dynseg[-1+ z_rsz].d_val); |
2997 | 0 | if ((u64_t)file_size <= relsz) { |
2998 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
2999 | 0 | "bad Elf64_Dynamic[DT_RELASZ] %#llx\n", |
3000 | 0 | relsz); |
3001 | 0 | throwCantPack(msg); |
3002 | 0 | } |
3003 | 0 | Elf64_Rela *last = (Elf64_Rela *)(relsz + (char *)rp); |
3004 | 0 | for (; rp < last; ++rp) { |
3005 | 0 | upx_uint64_t r_va = get_te64(&rp->r_offset); |
3006 | 0 | if (r_va == user_init_ava) { // found the Elf64_Rela |
3007 | 0 | user_init_rp = rp; |
3008 | 0 | upx_uint64_t r_info = get_te64(&rp->r_info); |
3009 | 0 | unsigned r_type = ELF64_R_TYPE(r_info); |
3010 | 0 | set_te32(&dynsym[0].st_name, r_va); // for decompressor |
3011 | 0 | set_te64(&dynsym[0].st_value, r_info); |
3012 | 0 | set_te64(&dynsym[0].st_size, get_te64(&rp->r_addend)); |
3013 | 0 | if (Elf64_Ehdr::EM_AARCH64 == e_machine) { |
3014 | 0 | if (R_AARCH64_RELATIVE == r_type) { |
3015 | 0 | user_init_va = get_te64(&rp->r_addend); |
3016 | 0 | } |
3017 | 0 | else if (R_AARCH64_ABS64 == r_type) { |
3018 | 0 | user_init_va = get_te64(&dynsym[ELF64_R_SYM(r_info)].st_value); |
3019 | 0 | } |
3020 | 0 | else { |
3021 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
3022 | 0 | "bad relocation %#llx DT_INIT_ARRAY[0]", |
3023 | 0 | r_info); |
3024 | 0 | throwCantPack(msg); |
3025 | 0 | } |
3026 | 0 | } |
3027 | 0 | else if (Elf64_Ehdr::EM_X86_64 == e_machine) { |
3028 | 0 | if (R_X86_64_RELATIVE == r_type) { |
3029 | 0 | user_init_va = get_te64(&rp->r_addend); |
3030 | 0 | } |
3031 | 0 | else if (R_X86_64_64 == r_type) { |
3032 | 0 | user_init_va = get_te64(&dynsym[ELF64_R_SYM(r_info)].st_value); |
3033 | 0 | } |
3034 | 0 | else { |
3035 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
3036 | 0 | "bad relocation %#llx DT_INIT_ARRAY[0]", |
3037 | 0 | r_info); |
3038 | 0 | throwCantPack(msg); |
3039 | 0 | } |
3040 | 0 | } |
3041 | 0 | break; |
3042 | 0 | } |
3043 | 0 | } |
3044 | 0 | } |
3045 | 0 | unsigned const p_filesz = get_te64(&pload_x0->p_filesz); |
3046 | 0 | if (!((user_init_va - xct_va) < p_filesz)) { |
3047 | | // Not in executable portion of first executable PT_LOAD. |
3048 | 0 | if (0==user_init_va && is_asl) { |
3049 | | // Android allows (0 ==> skip) ? |
3050 | 0 | upx_dt_init = 0; // force steal of 'extra' DT_NULL |
3051 | | // XXX: FIXME: depends on SHT_DYNAMIC coming later |
3052 | 0 | } |
3053 | 0 | else { |
3054 | 0 | char msg[70]; snprintf(msg, sizeof(msg), |
3055 | 0 | "bad init address %#x in Elf64_Shdr[%d].%#x\n", |
3056 | 0 | (unsigned)user_init_va, -1+ e_shnum - j, user_init_off); |
3057 | 0 | throwCantPack(msg); |
3058 | 0 | } |
3059 | 0 | } |
3060 | 0 | } |
3061 | | // By default /usr/bin/ld leaves 4 extra DT_NULL to support pre-linking. |
3062 | | // Take one as a last resort. |
3063 | 0 | if ((Elf64_Dyn::DT_INIT==upx_dt_init || !upx_dt_init) |
3064 | 0 | && Elf64_Shdr::SHT_DYNAMIC == sh_type) { |
3065 | 0 | upx_uint64_t sh_offset = get_te64(&shdr->sh_offset); |
3066 | 0 | upx_uint64_t sh_size = get_te64(&shdr->sh_size); |
3067 | 0 | if ((upx_uint64_t)file_size < sh_size |
3068 | 0 | || (upx_uint64_t)file_size < sh_offset |
3069 | 0 | || ((upx_uint64_t)file_size - sh_offset) < sh_size) { |
3070 | 0 | throwCantPack("bad SHT_DYNAMIC"); |
3071 | 0 | } |
3072 | 0 | unsigned const n = sh_size / sizeof(Elf64_Dyn); |
3073 | 0 | Elf64_Dyn *dynp = (Elf64_Dyn *)&file_image[sh_offset]; |
3074 | 0 | for (; Elf64_Dyn::DT_NULL != dynp->d_tag; ++dynp) { |
3075 | 0 | if (upx_dt_init == get_te64(&dynp->d_tag)) { |
3076 | 0 | break; // re-found DT_INIT |
3077 | 0 | } |
3078 | 0 | } |
3079 | 0 | if ((1+ dynp) < (n+ dynseg)) { // not the terminator, so take it |
3080 | 0 | user_init_va = get_te64(&dynp->d_val); // 0 if (0==upx_dt_init) |
3081 | 0 | set_te64(&dynp->d_tag, upx_dt_init = Elf64_Dyn::DT_INIT); |
3082 | 0 | user_init_off = (char const *)&dynp->d_val - (char const *)&file_image[0]; |
3083 | 0 | } |
3084 | 0 | } |
3085 | 0 | } |
3086 | 0 | return xct_va; |
3087 | 0 | } |
3088 | | |
3089 | | tribool PackLinuxElf32::canPack() |
3090 | 0 | { |
3091 | 0 | union { |
3092 | 0 | unsigned char buf[MAX_ELF_HDR_32]; |
3093 | | //struct { Elf32_Ehdr ehdr; Elf32_Phdr phdr; } e; |
3094 | 0 | } u; |
3095 | 0 | COMPILE_TIME_ASSERT(sizeof(u.buf) <= (2*512)) |
3096 | | |
3097 | | // My earlier design with "extra" Shdrs in output at xct_off |
3098 | | // DOES NOT WORK because code for EM_ARM has embedded relocations |
3099 | | // that are not made visible, such as: |
3100 | | // ----- glibc-2.31/sysdeps/arm/crti.S |
3101 | | // .type call_weak_fn, %function |
3102 | | // call_weak_fn: |
3103 | | // ldr r3, .LGOT |
3104 | | // ldr r2, .LGOT+4 |
3105 | | // .LPIC: |
3106 | | // add r3, pc, r3 |
3107 | | // ldr r2, [r3, r2] |
3108 | | // cmp r2, #0 |
3109 | | // bxeq lr |
3110 | | // b PREINIT_FUNCTION |
3111 | | // .p2align 2 |
3112 | | // .LGOT: |
3113 | | // .word _GLOBAL_OFFSET_TABLE_-(.LPIC+8) // unseen reloc! |
3114 | | // .word PREINIT_FUNCTION(GOT) |
3115 | | // ----- |
3116 | | // So, PackUnix::PackUnix() disables (but silently accepts) --android-shlib, |
3117 | | // and see if appending ARM_ATTRIBUTES Shdr is good enough. |
3118 | |
|
3119 | 0 | fi->seek(0, SEEK_SET); |
3120 | 0 | fi->readx(u.buf, sizeof(u.buf)); |
3121 | 0 | fi->seek(0, SEEK_SET); |
3122 | 0 | Elf32_Ehdr const *const ehdr = (Elf32_Ehdr *) u.buf; |
3123 | | |
3124 | | // now check the ELF header |
3125 | 0 | if (checkEhdr(ehdr) != 0) |
3126 | 0 | return false; |
3127 | | |
3128 | | // additional requirements for linux/elf386 |
3129 | 0 | if (get_te16(&ehdr->e_ehsize) != sizeof(*ehdr)) { |
3130 | 0 | throwCantPack("invalid Ehdr e_ehsize; try '--force-execve'"); |
3131 | 0 | return false; |
3132 | 0 | } |
3133 | 0 | if (e_phoff != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr |
3134 | 0 | throwCantPack("non-contiguous Ehdr/Phdr; try '--force-execve'"); |
3135 | 0 | return false; |
3136 | 0 | } |
3137 | | |
3138 | 0 | if (!canPackOSABI((Elf32_Ehdr *)u.buf)) { |
3139 | 0 | return false; |
3140 | 0 | } |
3141 | 0 | upx_uint32_t max_LOADsz = 0, max_offset = 0; |
3142 | 0 | Elf32_Phdr *phdr = phdri; |
3143 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
3144 | 0 | if (j > ((MAX_ELF_HDR_32 - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))) { |
3145 | 0 | throwCantPack("too many ElfXX_Phdr; try '--force-execve'"); |
3146 | 0 | return false; |
3147 | 0 | } |
3148 | 0 | if (is_LOAD(phdr)) { |
3149 | | // The first PT_LOAD must cover the beginning of the file (0==p_offset). |
3150 | 0 | upx_uint32_t const p_offset = get_te32(&phdr->p_offset); |
3151 | 0 | if (1!= exetype) { |
3152 | 0 | exetype = 1; |
3153 | 0 | load_va = get_te32(&phdr->p_vaddr); // class data member |
3154 | 0 | upx_uint32_t const off = ~page_mask & (upx_uint32_t)load_va; |
3155 | 0 | if (off && off == p_offset) { // specific hint |
3156 | 0 | throwCantPack("Go-language PT_LOAD: try hemfix.c, or try '--force-execve'"); |
3157 | | // Fixing it inside upx fails because packExtent() reads original file. |
3158 | 0 | return false; |
3159 | 0 | } |
3160 | 0 | if (0 != p_offset) { // 1st PT_LOAD must cover Ehdr and Phdr |
3161 | 0 | throwCantPack("first PT_LOAD.p_offset != 0; try '--force-execve'"); |
3162 | 0 | return false; |
3163 | 0 | } |
3164 | | // FIXME: bad for shlib! |
3165 | 0 | hatch_off = ~3ul & (3+ get_te32(&phdr->p_memsz)); |
3166 | 0 | } |
3167 | 0 | max_LOADsz = UPX_MAX(max_LOADsz, UPX_MIN(0x200000u, get_te32(&phdr->p_align))); |
3168 | 0 | unsigned filesz = get_te32(&phdr->p_filesz); |
3169 | 0 | max_LOADsz = UPX_MAX(max_LOADsz, filesz); |
3170 | 0 | max_offset = UPX_MAX(max_offset, filesz + p_offset); |
3171 | 0 | } |
3172 | 0 | } |
3173 | 0 | if (canUnpack()) { |
3174 | 0 | throwAlreadyPacked(); |
3175 | 0 | } |
3176 | | // Heuristic for lopped trailing PackHeader (packed and "hacked"!) |
3177 | 0 | if (3 == e_phnum // not shlib: PT_LOAD.C_BASE, PT_LOAD.C_TEXT, PT_GNU_STACK |
3178 | 0 | && UPX_MAGIC_LE32 == get_le32(&((l_info *)&phdri[e_phnum])->l_magic)) { |
3179 | 0 | throwAlreadyPacked(); |
3180 | 0 | } |
3181 | | // We want to compress position-independent executable (gcc -pie) |
3182 | | // main programs, but compressing a shared library must be avoided |
3183 | | // because the result is no longer usable. In theory, there is no way |
3184 | | // to tell them apart: both are just ET_DYN. Also in theory, |
3185 | | // neither the presence nor the absence of any particular symbol name |
3186 | | // can be used to tell them apart; there are counterexamples. |
3187 | | // However, we will use the following heuristic suggested by |
3188 | | // Peter S. Mazinger <ps.m@gmx.net> September 2005: |
3189 | | // If a ET_DYN has __libc_start_main as a global undefined symbol, |
3190 | | // then the file is a position-independent executable main program |
3191 | | // (that depends on libc.so.6) and is eligible to be compressed. |
3192 | | // Otherwise (no __libc_start_main as global undefined): skip it. |
3193 | | // Also allow __uClibc_main and __uClibc_start_main . |
3194 | | |
3195 | 0 | if (Elf32_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) { |
3196 | | // The DT_SYMTAB has no designated length. Read the whole file. |
3197 | 0 | alloc_file_image(file_image, file_size); |
3198 | 0 | fi->seek(0, SEEK_SET); |
3199 | 0 | fi->readx(file_image, file_size); |
3200 | 0 | memcpy(&ehdri, ehdr, sizeof(Elf32_Ehdr)); |
3201 | 0 | phdri= (Elf32_Phdr *)((size_t)e_phoff + file_image); // do not free() !! |
3202 | 0 | shdri= (Elf32_Shdr *)((size_t)e_shoff + file_image); // do not free() !! |
3203 | |
|
3204 | 0 | sec_strndx = nullptr; |
3205 | 0 | shstrtab = nullptr; |
3206 | 0 | if (e_shnum) { |
3207 | 0 | e_shstrndx = get_te16(&ehdr->e_shstrndx); |
3208 | 0 | if (e_shstrndx) { |
3209 | 0 | if (e_shnum <= e_shstrndx) { |
3210 | 0 | char msg[40]; snprintf(msg, sizeof(msg), |
3211 | 0 | "bad e_shstrndx %#x >= e_shnum %d", e_shstrndx, e_shnum); |
3212 | 0 | throwCantPack(msg); |
3213 | 0 | } |
3214 | 0 | sec_strndx = &shdri[e_shstrndx]; |
3215 | 0 | unsigned const sh_offset = get_te32(&sec_strndx->sh_offset); |
3216 | 0 | if ((u32_t)file_size <= sh_offset) { |
3217 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
3218 | 0 | "bad .e_shstrndx->sh_offset %#x", sh_offset); |
3219 | 0 | throwCantPack(msg); |
3220 | 0 | } |
3221 | 0 | shstrtab = (char const *)(sh_offset + file_image); |
3222 | 0 | } |
3223 | 0 | sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM); |
3224 | 0 | if (sec_dynsym) { |
3225 | 0 | unsigned const sh_link = get_te32(&sec_dynsym->sh_link); |
3226 | 0 | if (e_shnum <= sh_link) { |
3227 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
3228 | 0 | "bad SHT_DYNSYM.sh_link %#x", sh_link); |
3229 | 0 | } |
3230 | 0 | sec_dynstr = &shdri[sh_link]; |
3231 | 0 | } |
3232 | |
|
3233 | 0 | if (sec_strndx) { |
3234 | 0 | unsigned const sh_name = get_te32(&sec_strndx->sh_name); |
3235 | 0 | if (Elf32_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type) |
3236 | 0 | || (u32_t)file_size <= (sizeof(".shstrtab") |
3237 | 0 | + sh_name + (shstrtab - (const char *)&file_image[0])) |
3238 | 0 | || (sh_name |
3239 | 0 | && 0!=strcmp((char const *)".shstrtab", &shstrtab[sh_name])) |
3240 | 0 | ) { |
3241 | 0 | throwCantPack("bad e_shstrtab"); |
3242 | 0 | } |
3243 | 0 | } |
3244 | 0 | } |
3245 | | |
3246 | 0 | Elf32_Phdr const *pload_x0(nullptr); // first eXecutable PT_LOAD |
3247 | 0 | phdr= phdri; |
3248 | 0 | for (int j= e_phnum; --j>=0; ++phdr) |
3249 | 0 | if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { |
3250 | 0 | unsigned offset = check_pt_dynamic(phdr); |
3251 | 0 | dynseg= (Elf32_Dyn *)(offset + file_image); |
3252 | 0 | invert_pt_dynamic(dynseg, |
3253 | 0 | umin(get_te32(&phdr->p_filesz), (unsigned)(file_size_u - offset))); |
3254 | 0 | } |
3255 | 0 | else if (is_LOAD(phdr)) { |
3256 | 0 | if (!pload_x0 |
3257 | 0 | && Elf32_Phdr::PF_X & get_te32(&phdr->p_flags) |
3258 | 0 | ) { |
3259 | 0 | pload_x0 = phdr; |
3260 | 0 | } |
3261 | 0 | check_pt_load(phdr); |
3262 | 0 | } |
3263 | 0 | if (!pload_x0) { |
3264 | 0 | throwCantPack("No PT_LOAD has (p_flags & PF_X)"); |
3265 | 0 | } |
3266 | | // elf_find_dynamic() returns 0 if 0==dynseg. |
3267 | 0 | dynstr= (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB); |
3268 | 0 | dynsym= (Elf32_Sym /*const*/ *)elf_find_dynamic(Elf32_Dyn::DT_SYMTAB); |
3269 | |
|
3270 | 0 | if (opt->o_unix.force_pie |
3271 | 0 | || Elf32_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf32_Dyn::DT_FLAGS_1) |
3272 | 0 | || calls_crt1((Elf32_Rel const *)elf_find_dynamic(Elf32_Dyn::DT_REL), |
3273 | 0 | (int)elf_unsigned_dynamic(Elf32_Dyn::DT_RELSZ)) |
3274 | 0 | || calls_crt1((Elf32_Rel const *)elf_find_dynamic(Elf32_Dyn::DT_JMPREL), |
3275 | 0 | (int)elf_unsigned_dynamic(Elf32_Dyn::DT_PLTRELSZ))) { |
3276 | 0 | is_pie = true; // UNUSED except to ignore is_shlib and xct_off |
3277 | 0 | goto proceed; // calls C library init for main program |
3278 | 0 | } |
3279 | | |
3280 | 0 | if (Elf32_Ehdr::EM_ARM==get_te16(&ehdri.e_machine)) { |
3281 | 0 | sec_arm_attr = elf_find_section_type(Elf32_Shdr::SHT_ARM_ATTRIBUTES); |
3282 | 0 | if (Elf32_Ehdr::ET_DYN == e_type) { |
3283 | | // See earlier comment in this function. is_asl does not work. |
3284 | | //is_asl = (!!saved_opt_android_shlib) << 1; // bit 1; see is_shlib |
3285 | 0 | is_asl = 0; |
3286 | 0 | } |
3287 | 0 | } |
3288 | | |
3289 | | // Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.) |
3290 | | // If there is an existing DT_INIT, and if everything that the dynamic |
3291 | | // linker ld-linux needs to perform relocations before calling DT_INIT |
3292 | | // resides below the first SHT_EXECINSTR Section in one PT_LOAD, then |
3293 | | // compress from the first executable Section to the end of that PT_LOAD. |
3294 | | // We must not alter anything that ld-linux might touch before it calls |
3295 | | // the DT_INIT function. |
3296 | | // |
3297 | | // Obviously this hack requires that the linker script put pieces |
3298 | | // into good positions when building the original shared library, |
3299 | | // and also requires ld-linux to behave. |
3300 | |
|
3301 | 0 | if (/*jni_onload_sym ||*/ elf_find_dynamic(upx_dt_init)) { |
3302 | 0 | if (this->e_machine!=Elf32_Ehdr::EM_386 |
3303 | 0 | && this->e_machine!=Elf32_Ehdr::EM_MIPS |
3304 | 0 | && this->e_machine!=Elf32_Ehdr::EM_ARM) |
3305 | 0 | goto abandon; // need stub: EM_PPC |
3306 | 0 | if (elf_has_dynamic(Elf32_Dyn::DT_TEXTREL)) { |
3307 | 0 | throwCantPack("DT_TEXTREL found; re-compile with -fPIC"); |
3308 | 0 | goto abandon; |
3309 | 0 | } |
3310 | 0 | if (!(Elf32_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf32_Dyn::DT_FLAGS_1))) { |
3311 | | // not explicitly PIE main program |
3312 | 0 | if (Elf32_Ehdr::EM_ARM == e_machine // Android is common |
3313 | 0 | && 0 && !is_asl // but not explicit |
3314 | 0 | ) { |
3315 | 0 | opt->info_mode++; |
3316 | 0 | info("note: use --android-shlib if appropriate"); |
3317 | 0 | opt->info_mode--; |
3318 | 0 | } |
3319 | 0 | } |
3320 | 0 | if (Elf32_Ehdr::EM_MIPS == get_te16(&ehdr->e_machine) |
3321 | 0 | || Elf32_Ehdr::EM_PPC == get_te16(&ehdr->e_machine)) { |
3322 | 0 | throwCantPack("This test UPX cannot pack .so for MIPS or PowerPC; coming soon."); |
3323 | 0 | } |
3324 | 0 | xct_va = ~(upx_uint64_t)0; |
3325 | 0 | if (e_shnum) { |
3326 | 0 | xct_va = canPack_Shdr(pload_x0); |
3327 | 0 | } |
3328 | 0 | else { // no Sections; use heuristics |
3329 | 0 | unsigned const strsz = elf_unsigned_dynamic(Elf32_Dyn::DT_STRSZ); |
3330 | 0 | unsigned const strtab = elf_unsigned_dynamic(Elf32_Dyn::DT_STRTAB); |
3331 | 0 | unsigned const relsz = elf_unsigned_dynamic(Elf32_Dyn::DT_RELSZ); |
3332 | 0 | unsigned const rel = elf_unsigned_dynamic(Elf32_Dyn::DT_REL); |
3333 | 0 | unsigned const init = elf_unsigned_dynamic(upx_dt_init); |
3334 | 0 | if ((init == (relsz + rel ) && rel == (strsz + strtab)) |
3335 | 0 | || (init == (strsz + strtab) && strtab == (relsz + rel )) |
3336 | 0 | ) { |
3337 | 0 | xct_va = init; |
3338 | 0 | user_init_va = init; |
3339 | 0 | user_init_off = elf_get_offset_from_address(init); |
3340 | 0 | } |
3341 | 0 | } |
3342 | | // Rely on 0==elf_unsigned_dynamic(tag) if no such tag. |
3343 | 0 | unsigned const va_gash = elf_unsigned_dynamic(Elf32_Dyn::DT_GNU_HASH); |
3344 | 0 | unsigned const va_hash = elf_unsigned_dynamic(Elf32_Dyn::DT_HASH); |
3345 | 0 | unsigned y = 0; |
3346 | 0 | if ((y=1, xct_va < va_gash) || (y=2, (0==va_gash && xct_va < va_hash)) |
3347 | 0 | || (y=3, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_STRTAB)) |
3348 | 0 | || (y=4, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_SYMTAB)) |
3349 | 0 | || (y=5, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_REL)) |
3350 | 0 | || (y=6, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_RELA)) |
3351 | 0 | || (y=7, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_JMPREL)) |
3352 | 0 | || (y=8, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_VERDEF)) |
3353 | 0 | || (y=9, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_VERSYM)) |
3354 | 0 | || (y=10, xct_va < elf_unsigned_dynamic(Elf32_Dyn::DT_VERNEED)) ) { |
3355 | 0 | static char const *which[] = { |
3356 | 0 | "unknown", |
3357 | 0 | "DT_GNU_HASH", |
3358 | 0 | "DT_HASH", |
3359 | 0 | "DT_STRTAB", |
3360 | 0 | "DT_SYMTAB", |
3361 | 0 | "DT_REL", |
3362 | 0 | "DT_RELA", |
3363 | 0 | "DT_JMPREL", |
3364 | 0 | "DT_VERDEF", |
3365 | 0 | "DT_VERSYM", |
3366 | 0 | "DT_VERNEED", |
3367 | 0 | }; |
3368 | 0 | char buf[30]; snprintf(buf, sizeof(buf), "%s above stub", which[y]); |
3369 | 0 | throwCantPack(buf); |
3370 | 0 | goto abandon; |
3371 | 0 | } |
3372 | 0 | xct_off = elf_get_offset_from_address(xct_va); |
3373 | 0 | if (opt->debug.debug_level) { |
3374 | 0 | fprintf(stderr, "shlib canPack: xct_va=%#lx xct_off=%#lx\n", |
3375 | 0 | (long)xct_va, (long)xct_off); |
3376 | 0 | } |
3377 | 0 | goto proceed; // But proper packing depends on checking xct_va. |
3378 | 0 | } |
3379 | 0 | else { |
3380 | 0 | throwCantPack("need DT_INIT; try \"void _init(void){}\""); |
3381 | 0 | } |
3382 | 0 | abandon: |
3383 | 0 | return false; |
3384 | 0 | proceed: ; |
3385 | 0 | } |
3386 | | // XXX Theoretically the following test should be first, |
3387 | | // but PackUnix::canPack() wants 0!=exetype ? |
3388 | 0 | if (!super::canPack()) |
3389 | 0 | return false; |
3390 | 0 | assert(exetype == 1); |
3391 | 0 | exetype = 0; |
3392 | | |
3393 | | // set options |
3394 | | // this->blocksize: avoid over-allocating. |
3395 | | // (file_size - max_offset): debug info, non-globl symbols, etc. |
3396 | 0 | opt->o_unix.blocksize = blocksize = UPX_MAX(max_LOADsz, (unsigned)(file_size - max_offset)); |
3397 | 0 | return true; |
3398 | 0 | } |
3399 | | |
3400 | | tribool PackLinuxElf64::canUnpack() // bool, except -1: format known, but not packed |
3401 | 65.2k | { |
3402 | 65.2k | if (checkEhdr(&ehdri)) { |
3403 | 63.9k | return false; |
3404 | 63.9k | } |
3405 | 1.35k | if (get_te16(&ehdri.e_phnum) < 2) { |
3406 | 22 | throwCantUnpack("e_phnum must be >= 2"); |
3407 | 22 | } |
3408 | 1.33k | if (Elf64_Ehdr::ET_DYN==get_te16(&ehdri.e_type)) { |
3409 | 296 | PackLinuxElf64help1(fi); |
3410 | 296 | } |
3411 | 1.33k | if (super::canUnpack()) { |
3412 | 801 | return true; |
3413 | 801 | } |
3414 | 530 | return false; |
3415 | 1.33k | } |
3416 | | |
3417 | | tribool PackLinuxElf64::canPack() |
3418 | 0 | { |
3419 | 0 | union { |
3420 | 0 | unsigned char buf[MAX_ELF_HDR_64]; |
3421 | | //struct { Elf64_Ehdr ehdr; Elf64_Phdr phdr; } e; |
3422 | 0 | } u; |
3423 | 0 | COMPILE_TIME_ASSERT(sizeof(u) <= (2*1024)) |
3424 | |
|
3425 | 0 | fi->readx(u.buf, sizeof(u.buf)); |
3426 | 0 | fi->seek(0, SEEK_SET); |
3427 | 0 | Elf64_Ehdr const *const ehdr = (Elf64_Ehdr *) u.buf; |
3428 | | |
3429 | | // now check the ELF header |
3430 | 0 | if (checkEhdr(ehdr) != 0) |
3431 | 0 | return false; |
3432 | | |
3433 | | // additional requirements for linux/elf386 |
3434 | 0 | if (get_te16(&ehdr->e_ehsize) != sizeof(*ehdr)) { |
3435 | 0 | throwCantPack("invalid Ehdr e_ehsize; try '--force-execve'"); |
3436 | 0 | return false; |
3437 | 0 | } |
3438 | 0 | if (e_phoff != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr |
3439 | 0 | throwCantPack("non-contiguous Ehdr/Phdr; try '--force-execve'"); |
3440 | 0 | return false; |
3441 | 0 | } |
3442 | | |
3443 | 0 | upx_uint64_t max_LOADsz = 0, max_offset = 0; |
3444 | 0 | Elf64_Phdr const *phdr = phdri; |
3445 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
3446 | 0 | if (j > ((MAX_ELF_HDR_64 - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))) { |
3447 | 0 | throwCantPack("too many ElfXX_Phdr; try '--force-execve'"); |
3448 | 0 | return false; |
3449 | 0 | } |
3450 | 0 | if (is_LOAD(phdr)) { |
3451 | | // The first PT_LOAD must cover the beginning of the file (0==p_offset). |
3452 | 0 | upx_uint64_t const p_offset = get_te64(&phdr->p_offset); |
3453 | 0 | if (1!= exetype) { |
3454 | 0 | exetype = 1; |
3455 | 0 | load_va = get_te64(&phdr->p_vaddr); // class data member |
3456 | 0 | upx_uint64_t const off = ~page_mask & load_va; |
3457 | 0 | if (off && off == p_offset) { // specific hint |
3458 | 0 | throwCantPack("Go-language PT_LOAD: try hemfix.c, or try '--force-execve'"); |
3459 | | // Fixing it inside upx fails because packExtent() reads original file. |
3460 | 0 | return false; |
3461 | 0 | } |
3462 | 0 | if (0 != p_offset) { // 1st PT_LOAD must cover Ehdr and Phdr |
3463 | 0 | throwCantPack("first PT_LOAD.p_offset != 0; try '--force-execve'"); |
3464 | 0 | return false; |
3465 | 0 | } |
3466 | | // FIXME: bad for shlib! |
3467 | 0 | hatch_off = ~3ul & (3+ get_te64(&phdr->p_memsz)); |
3468 | 0 | } |
3469 | 0 | upx_uint64_t align = get_te64(&phdr->p_align); |
3470 | 0 | if (0x200000ul < align) align = 0x200000ul; // UPX_MIN type problem |
3471 | 0 | max_LOADsz = UPX_MAX(max_LOADsz, align); |
3472 | 0 | upx_uint64_t filesz = get_te64(&phdr->p_filesz); |
3473 | 0 | max_LOADsz = UPX_MAX(max_LOADsz, filesz); |
3474 | 0 | max_offset = UPX_MAX(max_offset, filesz + p_offset); |
3475 | 0 | } |
3476 | 0 | } |
3477 | 0 | if (canUnpack()) { |
3478 | 0 | throwAlreadyPacked(); |
3479 | 0 | } |
3480 | | // Heuristic for lopped trailing PackHeader (packed and "hacked"!) |
3481 | 0 | if (3 == e_phnum // not shlib: PT_LOAD.C_BASE, PT_LOAD.C_TEXT, PT_GNU_STACK |
3482 | 0 | && UPX_MAGIC_LE32 == get_le32(&((l_info *)&phdri[e_phnum])->l_magic)) { |
3483 | 0 | throwAlreadyPacked(); |
3484 | 0 | } |
3485 | | // We want to compress position-independent executable (gcc -pie) |
3486 | | // main programs, but compressing a shared library must be avoided |
3487 | | // because the result is no longer usable. In theory, there is no way |
3488 | | // to tell them apart: both are just ET_DYN. Also in theory, |
3489 | | // neither the presence nor the absence of any particular symbol name |
3490 | | // can be used to tell them apart; there are counterexamples. |
3491 | | // However, we will use the following heuristic suggested by |
3492 | | // Peter S. Mazinger <ps.m@gmx.net> September 2005: |
3493 | | // If a ET_DYN has __libc_start_main as a global undefined symbol, |
3494 | | // then the file is a position-independent executable main program |
3495 | | // (that depends on libc.so.6) and is eligible to be compressed. |
3496 | | // Otherwise (no __libc_start_main as global undefined): skip it. |
3497 | | // Also allow __uClibc_main and __uClibc_start_main . |
3498 | | |
3499 | 0 | if (Elf64_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) { |
3500 | | // The DT_SYMTAB has no designated length. Read the whole file. |
3501 | 0 | alloc_file_image(file_image, file_size); |
3502 | 0 | fi->seek(0, SEEK_SET); |
3503 | 0 | fi->readx(file_image, file_size); |
3504 | 0 | memcpy(&ehdri, ehdr, sizeof(Elf64_Ehdr)); |
3505 | 0 | phdri= (Elf64_Phdr *)((size_t)e_phoff + file_image); // do not free() !! |
3506 | 0 | shdri= (Elf64_Shdr *)((size_t)e_shoff + file_image); // do not free() !! |
3507 | |
|
3508 | 0 | sec_strndx = nullptr; |
3509 | 0 | shstrtab = nullptr; |
3510 | 0 | if (e_shnum) { |
3511 | 0 | e_shstrndx = get_te16(&ehdr->e_shstrndx); |
3512 | 0 | if (e_shstrndx) { |
3513 | 0 | if (e_shnum <= e_shstrndx) { |
3514 | 0 | char msg[40]; snprintf(msg, sizeof(msg), |
3515 | 0 | "bad e_shstrndx %#x >= e_shnum %d", e_shstrndx, e_shnum); |
3516 | 0 | throwCantPack(msg); |
3517 | 0 | } |
3518 | 0 | sec_strndx = &shdri[e_shstrndx]; |
3519 | 0 | upx_uint64_t sh_offset = get_te64(&sec_strndx->sh_offset); |
3520 | 0 | if ((u64_t)file_size <= sh_offset) { |
3521 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
3522 | 0 | "bad .e_shstrndx->sh_offset %#lx", (long unsigned)sh_offset); |
3523 | 0 | throwCantPack(msg); |
3524 | 0 | } |
3525 | 0 | shstrtab = (char const *)(sh_offset + file_image); |
3526 | 0 | } |
3527 | 0 | sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM); |
3528 | 0 | if (sec_dynsym) { |
3529 | 0 | unsigned const sh_link = get_te32(&sec_dynsym->sh_link); |
3530 | 0 | if (e_shnum <= sh_link) { |
3531 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
3532 | 0 | "bad SHT_DYNSYM.sh_link %#x", sh_link); |
3533 | 0 | } |
3534 | 0 | sec_dynstr = &shdri[sh_link]; |
3535 | 0 | } |
3536 | |
|
3537 | 0 | if (sec_strndx) { |
3538 | 0 | unsigned const sh_name = get_te32(&sec_strndx->sh_name); |
3539 | 0 | if (Elf64_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type) |
3540 | 0 | || (u32_t)file_size <= (sizeof(".shstrtab") |
3541 | 0 | + sh_name + (shstrtab - (const char *)&file_image[0])) |
3542 | 0 | || (sh_name |
3543 | 0 | && 0!=strcmp((char const *)".shstrtab", &shstrtab[sh_name])) |
3544 | 0 | ) { |
3545 | 0 | throwCantPack("bad e_shstrtab"); |
3546 | 0 | } |
3547 | 0 | } |
3548 | 0 | } |
3549 | | |
3550 | 0 | Elf64_Phdr const *pload_x0(nullptr); // first eXecutable PT_LOAD |
3551 | 0 | phdr= phdri; |
3552 | 0 | for (int j= e_phnum; --j>=0; ++phdr) |
3553 | 0 | if (Elf64_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { |
3554 | 0 | upx_uint64_t offset = check_pt_dynamic(phdr); |
3555 | 0 | dynseg= (Elf64_Dyn *)(offset + file_image); |
3556 | 0 | invert_pt_dynamic(dynseg, |
3557 | 0 | umin(get_te64(&phdr->p_filesz), file_size - offset)); |
3558 | 0 | } |
3559 | 0 | else if (is_LOAD(phdr)) { |
3560 | 0 | if (!pload_x0 |
3561 | 0 | && Elf64_Phdr::PF_X & get_te32(&phdr->p_flags) |
3562 | 0 | ) { |
3563 | 0 | pload_x0 = phdr; |
3564 | 0 | } |
3565 | 0 | check_pt_load(phdr); |
3566 | 0 | } |
3567 | 0 | if (!pload_x0) { |
3568 | 0 | throwCantPack("No PT_LOAD has (p_flags & PF_X)"); |
3569 | 0 | } |
3570 | | // elf_find_dynamic() returns 0 if 0==dynseg. |
3571 | 0 | dynstr= (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB); |
3572 | 0 | dynsym= (Elf64_Sym /*const*/ *)elf_find_dynamic(Elf64_Dyn::DT_SYMTAB); |
3573 | |
|
3574 | 0 | if (opt->o_unix.force_pie |
3575 | 0 | || Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1) |
3576 | 0 | || calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_RELA), |
3577 | 0 | (int)elf_unsigned_dynamic(Elf64_Dyn::DT_RELASZ)) |
3578 | 0 | || calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_JMPREL), |
3579 | 0 | (int)elf_unsigned_dynamic(Elf64_Dyn::DT_PLTRELSZ))) { |
3580 | 0 | is_pie = true; // UNUSED except to ignore is_shlib and xct_off |
3581 | 0 | goto proceed; // calls C library init for main program |
3582 | 0 | } |
3583 | | |
3584 | 0 | if (Elf64_Ehdr::EM_ARM==get_te16(&ehdri.e_machine)) { |
3585 | 0 | sec_arm_attr = elf_find_section_type(Elf64_Shdr::SHT_ARM_ATTRIBUTES); |
3586 | 0 | if (Elf64_Ehdr::ET_DYN == e_type) { |
3587 | | // See comment in Elf32_Linux::canPack(). is_asl does not work. |
3588 | | // 64-bit ARM (aarch64) also has no ARM_ATTRIBUTES. |
3589 | | //is_asl = (!!saved_opt_android_shlib) << 1; // bit 1; see is_shlib |
3590 | 0 | is_asl = 0; |
3591 | 0 | } |
3592 | 0 | } |
3593 | | |
3594 | | // Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.) |
3595 | | // If there is an existing DT_INIT, and if everything that the dynamic |
3596 | | // linker ld-linux needs to perform relocations before calling DT_INIT |
3597 | | // resides below the first SHT_EXECINSTR Section in one PT_LOAD, then |
3598 | | // compress from the first executable Section to the end of that PT_LOAD. |
3599 | | // We must not alter anything that ld-linux might touch before it calls |
3600 | | // the DT_INIT function. |
3601 | | // |
3602 | | // Obviously this hack requires that the linker script put pieces |
3603 | | // into good positions when building the original shared library, |
3604 | | // and also requires ld-linux to behave. |
3605 | |
|
3606 | 0 | if (/*jni_onload_sym ||*/ elf_find_dynamic(upx_dt_init)) { |
3607 | 0 | if (elf_has_dynamic(Elf64_Dyn::DT_TEXTREL)) { |
3608 | 0 | throwCantPack("DT_TEXTREL found; re-compile with -fPIC"); |
3609 | 0 | goto abandon; |
3610 | 0 | } |
3611 | 0 | if (!(Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1))) { |
3612 | | // not explicitly PIE main program |
3613 | 0 | if (Elf64_Ehdr::EM_AARCH64 == e_machine // Android is common |
3614 | 0 | && !is_asl // but not explicit |
3615 | 0 | ) { |
3616 | 0 | opt->info_mode++; |
3617 | 0 | info("note: use --android-shlib if appropriate"); |
3618 | 0 | opt->info_mode--; |
3619 | 0 | } |
3620 | 0 | } |
3621 | 0 | if (Elf64_Ehdr::EM_PPC64 == get_te16(&ehdr->e_machine)) { |
3622 | 0 | throwCantPack("This test UPX cannot pack .so for PowerPC64; coming soon."); |
3623 | 0 | } |
3624 | 0 | xct_va = ~(upx_uint64_t)0; |
3625 | 0 | if (e_shnum) { |
3626 | 0 | xct_va = canPack_Shdr(pload_x0); |
3627 | 0 | } |
3628 | 0 | else { // no Sections; use heuristics |
3629 | 0 | upx_uint64_t const strsz = elf_unsigned_dynamic(Elf64_Dyn::DT_STRSZ); |
3630 | 0 | upx_uint64_t const strtab = elf_unsigned_dynamic(Elf64_Dyn::DT_STRTAB); |
3631 | 0 | upx_uint64_t const relsz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELSZ); |
3632 | 0 | upx_uint64_t const rel = elf_unsigned_dynamic(Elf64_Dyn::DT_REL); |
3633 | 0 | upx_uint64_t const init = elf_unsigned_dynamic(upx_dt_init); |
3634 | 0 | if ((init == (relsz + rel ) && rel == (strsz + strtab)) |
3635 | 0 | || (init == (strsz + strtab) && strtab == (relsz + rel )) |
3636 | 0 | ) { |
3637 | 0 | xct_va = init; |
3638 | 0 | user_init_va = init; |
3639 | 0 | user_init_off = elf_get_offset_from_address(init); |
3640 | 0 | } |
3641 | 0 | } |
3642 | | // Rely on 0==elf_unsigned_dynamic(tag) if no such tag. |
3643 | 0 | upx_uint64_t const va_gash = elf_unsigned_dynamic(Elf64_Dyn::DT_GNU_HASH); |
3644 | 0 | upx_uint64_t const va_hash = elf_unsigned_dynamic(Elf64_Dyn::DT_HASH); |
3645 | 0 | unsigned y = 0; |
3646 | 0 | if ((y=1, xct_va < va_gash) || (y=2, (0==va_gash && xct_va < va_hash)) |
3647 | 0 | || (y=3, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_STRTAB)) |
3648 | 0 | || (y=4, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_SYMTAB)) |
3649 | 0 | || (y=5, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_REL)) |
3650 | 0 | || (y=6, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_RELA)) |
3651 | 0 | || (y=7, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_JMPREL)) |
3652 | 0 | || (y=8, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_VERDEF)) |
3653 | 0 | || (y=9, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_VERSYM)) |
3654 | 0 | || (y=10, xct_va < elf_unsigned_dynamic(Elf64_Dyn::DT_VERNEED)) ) { |
3655 | 0 | static char const *which[] = { |
3656 | 0 | "unknown", |
3657 | 0 | "DT_GNU_HASH", |
3658 | 0 | "DT_HASH", |
3659 | 0 | "DT_STRTAB", |
3660 | 0 | "DT_SYMTAB", |
3661 | 0 | "DT_REL", |
3662 | 0 | "DT_RELA", |
3663 | 0 | "DT_JMPREL", |
3664 | 0 | "DT_VERDEF", |
3665 | 0 | "DT_VERSYM", |
3666 | 0 | "DT_VERNEED", |
3667 | 0 | }; |
3668 | 0 | char buf[30]; snprintf(buf, sizeof(buf), "%s above stub", which[y]); |
3669 | 0 | throwCantPack(buf); |
3670 | 0 | goto abandon; |
3671 | 0 | } |
3672 | 0 | xct_off = elf_get_offset_from_address(xct_va); |
3673 | 0 | if (opt->debug.debug_level) { |
3674 | 0 | fprintf(stderr, "shlib canPack: xct_va=%#lx xct_off=%#lx\n", |
3675 | 0 | (long)xct_va, (long)xct_off); |
3676 | 0 | } |
3677 | 0 | goto proceed; // But proper packing depends on checking xct_va. |
3678 | 0 | } |
3679 | 0 | else { |
3680 | 0 | throwCantPack("need DT_INIT; try \"void _init(void){}\""); |
3681 | 0 | } |
3682 | 0 | abandon: |
3683 | 0 | return false; |
3684 | 0 | proceed: ; |
3685 | 0 | } |
3686 | | // XXX Theoretically the following test should be first, |
3687 | | // but PackUnix::canPack() wants 0!=exetype ? |
3688 | 0 | if (!super::canPack()) |
3689 | 0 | return false; |
3690 | 0 | assert(exetype == 1); |
3691 | 0 | exetype = 0; |
3692 | | |
3693 | | // set options |
3694 | | // this->blocksize: avoid over-allocating. |
3695 | | // (file_size - max_offset): debug info, non-globl symbols, etc. |
3696 | 0 | opt->o_unix.blocksize = blocksize = UPX_MAX(max_LOADsz, file_size - max_offset); |
3697 | 0 | return true; |
3698 | 0 | } |
3699 | | |
3700 | | off_t |
3701 | | PackLinuxElf32::getbrk(Elf32_Phdr const *phdr, int nph) const |
3702 | 0 | { |
3703 | 0 | off_t brka = 0; |
3704 | 0 | for (int j = 0; j < nph; ++phdr, ++j) { |
3705 | 0 | if (is_LOAD(phdr)) { |
3706 | 0 | off_t b = get_te32(&phdr->p_vaddr) + get_te32(&phdr->p_memsz); |
3707 | 0 | if (b > brka) |
3708 | 0 | brka = b; |
3709 | 0 | } |
3710 | 0 | } |
3711 | 0 | return brka; |
3712 | 0 | } |
3713 | | |
3714 | | off_t |
3715 | | PackLinuxElf32::getbase(const Elf32_Phdr *phdr, int nph) const |
3716 | 0 | { |
3717 | 0 | off_t base = ~0u; |
3718 | 0 | for (int j = 0; j < nph; ++phdr, ++j) { |
3719 | 0 | if (is_LOAD(phdr)) { |
3720 | 0 | unsigned const vaddr = get_te32(&phdr->p_vaddr); |
3721 | 0 | if (vaddr < (unsigned) base) |
3722 | 0 | base = vaddr; |
3723 | 0 | } |
3724 | 0 | } |
3725 | 0 | if (0!=base) { |
3726 | 0 | return base; |
3727 | 0 | } |
3728 | 0 | return 0x12000; |
3729 | 0 | } |
3730 | | |
3731 | | off_t |
3732 | | PackLinuxElf64::getbrk(const Elf64_Phdr *phdr, int nph) const |
3733 | 0 | { |
3734 | 0 | off_t brka = 0; |
3735 | 0 | for (int j = 0; j < nph; ++phdr, ++j) { |
3736 | 0 | if (is_LOAD(phdr)) { |
3737 | 0 | off_t b = get_te64(&phdr->p_vaddr) + get_te64(&phdr->p_memsz); |
3738 | 0 | if (b > brka) |
3739 | 0 | brka = b; |
3740 | 0 | } |
3741 | 0 | } |
3742 | 0 | return brka; |
3743 | 0 | } |
3744 | | |
3745 | | static unsigned |
3746 | | is_pow2(unsigned x) |
3747 | 0 | { |
3748 | 0 | return !((-1 + x) & x); |
3749 | 0 | } |
3750 | | |
3751 | | void |
3752 | | PackLinuxElf32::generateElfHdr( |
3753 | | OutputFile *fo, |
3754 | | void const *proto, |
3755 | | unsigned const brka |
3756 | | ) |
3757 | 0 | { |
3758 | 0 | cprElfHdr2 *const h2 = (cprElfHdr2 *)(void *)&elfout; |
3759 | 0 | cprElfHdr3 *const h3 = (cprElfHdr3 *)(void *)&elfout; |
3760 | 0 | h3->ehdr = ((cprElfHdr3 const *)proto)->ehdr; |
3761 | 0 | e_type = get_te16(&h3->ehdr.e_type); |
3762 | 0 | if (!memcmp("\x7f\x45\x4c\x46", proto, 4) && Elf32_Ehdr::ET_EXEC == e_type |
3763 | 0 | && 2 <= get_te16(&h3->ehdr.e_phnum)) { |
3764 | 0 | h3->phdr[C_BASE] = ((cprElfHdr3 const *)proto)->phdr[1]; // .data; .p_align |
3765 | 0 | h3->phdr[C_TEXT] = ((cprElfHdr3 const *)proto)->phdr[0]; // .text |
3766 | 0 | } |
3767 | 0 | else { |
3768 | 0 | memcpy(&h3->ehdr.e_ident[0], "\x7f\x45\x4c\x46", 4); |
3769 | 0 | h3->ehdr.e_ident[EI_CLASS] = ei_class; |
3770 | 0 | h3->ehdr.e_ident[EI_DATA] = ei_data; |
3771 | 0 | h3->ehdr.e_ident[EI_VERSION] = EV_CURRENT; |
3772 | 0 | h3->ehdr.e_ident[EI_OSABI] = ei_osabi; |
3773 | |
|
3774 | 0 | h3->ehdr.e_ident[EI_ABIVERSION] = ehdri.e_ident[EI_ABIVERSION]; // ei_abiversion ? |
3775 | | // Perhaps NT_GNU_ABI_TAG from Shdr .note.ABI-tag or PT_NOTE ? |
3776 | | // But that is much too recent (and un-standardized) for other software. |
3777 | |
|
3778 | 0 | set_te32(&h3->ehdr.e_phoff, sizeof(Elf32_Ehdr)); |
3779 | 0 | set_te16(&h3->ehdr.e_ehsize,sizeof(Elf32_Ehdr)); |
3780 | 0 | set_te16(&h3->ehdr.e_phentsize, sizeof(Elf32_Phdr)); |
3781 | 0 | set_te16(&h3->ehdr.e_phnum, 2); |
3782 | 0 | set_te16(&h3->ehdr.e_machine, e_machine); |
3783 | 0 | set_te16(&h3->ehdr.e_shstrndx, 0); |
3784 | 0 | memset(&h3->phdr[C_BASE], 0, sizeof(h3->phdr[C_BASE])); |
3785 | 0 | memset(&h3->phdr[C_TEXT], 0, sizeof(h3->phdr[C_TEXT])); |
3786 | 0 | memset(&h3->phdr[2 ], 0, sizeof(h3->phdr[2 ])); |
3787 | 0 | set_te32(&h3->phdr[C_BASE].p_flags, 0); |
3788 | 0 | set_te32(&h3->phdr[C_TEXT].p_flags, Elf32_Phdr::PF_X| Elf32_Phdr::PF_R); |
3789 | 0 | if (!memcmp("\x7f\x45\x4c\x46", proto, 4) && Elf32_Ehdr::ET_REL == e_type) { |
3790 | 0 | } |
3791 | 0 | else { |
3792 | 0 | throwCantPack("unknown e_type %#x", e_type); |
3793 | 0 | } |
3794 | 0 | } |
3795 | 0 | h3->ehdr.e_type = ehdri.e_type; // ET_EXEC vs ET_DYN (gcc -pie -fPIC) |
3796 | 0 | memset(&h3->linfo, 0, sizeof(h3->linfo)); |
3797 | |
|
3798 | 0 | h3->ehdr.e_ident[Elf32_Ehdr::EI_OSABI] = ei_osabi; |
3799 | 0 | if (Elf32_Ehdr::EM_MIPS==e_machine) { // MIPS R3000 FIXME |
3800 | 0 | h3->ehdr.e_ident[Elf32_Ehdr::EI_OSABI] = Elf32_Ehdr::ELFOSABI_NONE; |
3801 | 0 | h3->ehdr.e_flags = ehdri.e_flags; |
3802 | 0 | } |
3803 | |
|
3804 | 0 | if (ph.format != getFormat()) { |
3805 | 0 | assert(false); // unknown ph.format, PackLinuxElf32 |
3806 | 0 | } |
3807 | 0 | assert(get_te32(&h2->ehdr.e_phoff) == sizeof(Elf32_Ehdr)); |
3808 | 0 | assert(get_te16(&h2->ehdr.e_ehsize) == sizeof(Elf32_Ehdr)); |
3809 | 0 | assert(get_te16(&h2->ehdr.e_phentsize) == sizeof(Elf32_Phdr)); |
3810 | | |
3811 | 0 | h2->ehdr.e_shoff = 0; |
3812 | 0 | set_te16(&h2->ehdr.e_shentsize, sizeof(Elf32_Shdr)); // libbfd-2.41-38.fc40 |
3813 | 0 | if (o_elf_shnum) { |
3814 | 0 | h2->ehdr.e_shnum = o_elf_shnum; |
3815 | 0 | h2->ehdr.e_shstrndx = o_elf_shnum - 1; |
3816 | 0 | } |
3817 | 0 | else { |
3818 | | // https://bugzilla.redhat.com/show_bug.cgi?id=2131609 |
3819 | | // 0==.e_shnum is a special case for libbfd |
3820 | | // that requires 0==.e_shentsize in order to force "no Shdrs" |
3821 | | // But qemu 8.2.9 with libbfd-2.41-38.fc40 says EXEC format error |
3822 | | // and uses 0==.e_shoff instead. |
3823 | | // h2->ehdr.e_shentsize = 0; |
3824 | 0 | h2->ehdr.e_shnum = 0; |
3825 | 0 | h2->ehdr.e_shstrndx = 0; |
3826 | 0 | } |
3827 | |
|
3828 | 0 | unsigned phnum_o = 2 + n_phdrx; // C_BASE, C_TEXT |
3829 | 0 | set_te16(&h2->ehdr.e_phnum, phnum_o); |
3830 | | |
3831 | | // Info for OS kernel to set the brk() |
3832 | 0 | if (brka) { |
3833 | | // linux-2.6.14 binfmt_elf.c: SIGKILL if (0==.p_memsz) on a page boundary |
3834 | 0 | upx_uint32_t lo_va_user = ~0u; // infinity |
3835 | 0 | for (int j= e_phnum; --j>=0; ) { |
3836 | 0 | if (is_LOAD(&phdri[j])) { |
3837 | 0 | upx_uint32_t const vaddr = get_te32(&phdri[j].p_vaddr); |
3838 | 0 | lo_va_user = umin(lo_va_user, vaddr); |
3839 | 0 | } |
3840 | 0 | } |
3841 | 0 | set_te32( &h2->phdr[C_BASE].p_vaddr, lo_va_user); |
3842 | 0 | h2->phdr[C_BASE].p_paddr = h2->phdr[C_BASE].p_vaddr; |
3843 | 0 | h2->phdr[C_TEXT].p_vaddr = h2->phdr[C_BASE].p_vaddr; |
3844 | 0 | h2->phdr[C_TEXT].p_paddr = h2->phdr[C_BASE].p_vaddr; |
3845 | 0 | set_te32(&h2->phdr[C_BASE].p_type, PT_LOAD); // be sure |
3846 | 0 | set_te32(&h2->phdr[C_TEXT].p_type, PT_LOAD); // be sure |
3847 | 0 | h2->phdr[C_BASE].p_offset = 0; |
3848 | 0 | h2->phdr[C_BASE].p_filesz = 0; |
3849 | | // .p_memsz = brka; temporary until sz_pack2 |
3850 | 0 | set_te32(&h2->phdr[C_BASE].p_memsz, brka - lo_va_user); |
3851 | 0 | set_te32(&h2->phdr[C_BASE].p_flags, Elf32_Phdr::PF_R | Elf32_Phdr::PF_W); |
3852 | 0 | } |
3853 | 0 | set_te32(&h3->phdr[C_BASE].p_align, page_size); |
3854 | 0 | set_te32(&h3->phdr[C_TEXT].p_align, page_size); |
3855 | 0 | set_te32(&h2->phdr[C_TEXT].p_flags, ~Elf32_Phdr::PF_W & get_te32(&h2->phdr[C_TEXT].p_flags)); |
3856 | 0 | fo->write(h2, sizeof(Elf32_Ehdr) + 2* sizeof(Elf32_Phdr)); // C_BASE, C_TEXT |
3857 | |
|
3858 | 0 | u64_t const zero_pad = 0; |
3859 | 0 | unsigned uva0 = get_te32(&h2->phdr[C_TEXT].p_vaddr); |
3860 | 0 | unsigned off_o = 0; |
3861 | 0 | for (unsigned phase = 0; phase < 2; ++phase) { // 0: Phdrs; 1: bodies |
3862 | 0 | off_o = sizeof(Elf32_Ehdr) + phnum_o * sizeof(Elf32_Phdr); |
3863 | 0 | for (unsigned j = 0; j < n_phdrx; ++j) { |
3864 | 0 | Elf32_Phdr phtmp = *phdrx[j]; |
3865 | 0 | phtmp.p_vaddr = phtmp.p_paddr = 0; |
3866 | 0 | unsigned const off_i = get_te32(&phtmp.p_offset); |
3867 | 0 | unsigned const align = get_te32(&phtmp.p_align); |
3868 | 0 | unsigned const filesz = get_te32(&phtmp.p_filesz); |
3869 | 0 | unsigned pad = 0; |
3870 | 0 | if (filesz && align && is_pow2(align)) { |
3871 | 0 | unsigned alm1 = -1 + umin(8u, align); |
3872 | 0 | pad = alm1 & (0u - off_o); |
3873 | 0 | off_o += pad; |
3874 | 0 | set_te32(&phtmp.p_vaddr, off_o + uva0); phtmp.p_paddr = phtmp.p_vaddr; |
3875 | 0 | } |
3876 | 0 | if (0==phase) { |
3877 | 0 | set_te32(&phtmp.p_offset, (filesz ? off_o : 0)); |
3878 | 0 | fo->write(&phtmp, sizeof(phtmp)); // Phdr |
3879 | 0 | } |
3880 | 0 | if (1==phase) { |
3881 | 0 | if (pad) fo->write(&zero_pad, pad); |
3882 | 0 | if (filesz) fo->write(&file_image[off_i], filesz); // body |
3883 | 0 | } |
3884 | 0 | off_o += filesz; |
3885 | 0 | } |
3886 | 0 | } |
3887 | 0 | off_o = fpad4(fo, off_o); |
3888 | 0 | sz_phdrx = off_o - (sizeof(Elf32_Ehdr) + phnum_o * sizeof(Elf32_Phdr)); |
3889 | 0 | set_te32(&h2->phdr[C_BASE].p_filesz, off_o); |
3890 | |
|
3891 | 0 | sz_elf_hdrs = sizeof(Elf32_Ehdr) + phnum_o * sizeof(Elf32_Phdr) + sz_phdrx; |
3892 | 0 | overlay_offset = sz_elf_hdrs + sizeof(l_info); |
3893 | 0 | o_binfo = sz_elf_hdrs + sizeof(l_info) + sizeof(p_info); |
3894 | |
|
3895 | 0 | l_info linfo2; memset(&linfo2, 0, sizeof(linfo2)); |
3896 | 0 | fo->write(&linfo2, sizeof(linfo2)); |
3897 | 0 | } |
3898 | | |
3899 | | void |
3900 | | PackNetBSDElf32x86::generateElfHdr( |
3901 | | OutputFile *fo, |
3902 | | void const *proto, |
3903 | | unsigned const brka |
3904 | | ) |
3905 | 0 | { |
3906 | 0 | cprElfHdr2 *const h2 = (cprElfHdr2 *)(void *)&elfout; |
3907 | 0 | super::generateElfHdr(fo, proto, brka); |
3908 | |
|
3909 | 0 | sz_elf_hdrs = sizeof(*h2) - sizeof(linfo); |
3910 | 0 | unsigned note_offset = sz_elf_hdrs; |
3911 | | |
3912 | | // Find the NetBSD PT_NOTE and the PaX PT_NOTE. |
3913 | 0 | Elf32_Nhdr const *np_NetBSD = nullptr; unsigned sz_NetBSD = 0; |
3914 | 0 | Elf32_Nhdr const *np_PaX = nullptr; unsigned sz_PaX = 0; |
3915 | 0 | unsigned char *cp = (unsigned char *)note_body; |
3916 | 0 | unsigned j; |
3917 | 0 | for (j=0; j < note_size; ) { |
3918 | 0 | Elf32_Nhdr const *const np = (Elf32_Nhdr const *)(void *)cp; |
3919 | 0 | int k = sizeof(*np) + up4(get_te32(&np->namesz)) |
3920 | 0 | + up4(get_te32(&np->descsz)); |
3921 | |
|
3922 | 0 | if (NHDR_NETBSD_TAG == np->type && 7== np->namesz |
3923 | 0 | && NETBSD_DESCSZ == np->descsz |
3924 | 0 | && 0==strcmp(ELF_NOTE_NETBSD_NAME, |
3925 | 0 | /* &np->body */ (char const *)(1+ np))) { |
3926 | 0 | np_NetBSD = np; |
3927 | 0 | sz_NetBSD = k; |
3928 | 0 | } |
3929 | 0 | if (NHDR_PAX_TAG == np->type && 4== np->namesz |
3930 | 0 | && PAX_DESCSZ==np->descsz |
3931 | 0 | && 0==strcmp(ELF_NOTE_PAX_NAME, |
3932 | 0 | /* &np->body */ (char const *)(1+ np))) { |
3933 | 0 | np_PaX = np; |
3934 | 0 | sz_PaX = k; |
3935 | 0 | } |
3936 | 0 | cp += k; |
3937 | 0 | j += k; |
3938 | 0 | } |
3939 | | |
3940 | | // Add PT_NOTE for the NetBSD note and PaX note, if any. |
3941 | 0 | note_offset += (np_NetBSD ? sizeof(Elf32_Phdr) : 0); |
3942 | 0 | note_offset += (np_PaX ? sizeof(Elf32_Phdr) : 0); |
3943 | 0 | Elf32_Phdr *phdr = &elfout.phdr[C_NOTE]; |
3944 | 0 | if (np_NetBSD) { |
3945 | 0 | set_te32(&phdr->p_type, PT_NOTE32); |
3946 | 0 | set_te32(&phdr->p_offset, note_offset); |
3947 | 0 | set_te32(&phdr->p_vaddr, note_offset); |
3948 | 0 | set_te32(&phdr->p_paddr, note_offset); |
3949 | 0 | set_te32(&phdr->p_filesz, sz_NetBSD); |
3950 | 0 | set_te32(&phdr->p_memsz, sz_NetBSD); |
3951 | 0 | set_te32(&phdr->p_flags, Elf32_Phdr::PF_R); |
3952 | 0 | set_te32(&phdr->p_align, 4); |
3953 | |
|
3954 | 0 | sz_elf_hdrs += sz_NetBSD + sizeof(*phdr); |
3955 | 0 | note_offset += sz_NetBSD; |
3956 | 0 | ++phdr; |
3957 | 0 | } |
3958 | 0 | if (np_PaX) { |
3959 | 0 | set_te32(&phdr->p_type, PT_NOTE32); |
3960 | 0 | set_te32(&phdr->p_offset, note_offset); |
3961 | 0 | set_te32(&phdr->p_vaddr, note_offset); |
3962 | 0 | set_te32(&phdr->p_paddr, note_offset); |
3963 | 0 | set_te32(&phdr->p_filesz, sz_PaX); |
3964 | 0 | set_te32(&phdr->p_memsz, sz_PaX); |
3965 | 0 | set_te32(&phdr->p_flags, Elf32_Phdr::PF_R); |
3966 | 0 | set_te32(&phdr->p_align, 4); |
3967 | | |
3968 | | /* &np_PaX->body[4] */ |
3969 | 0 | const unsigned char *p4 = &(ACC_CCAST(const unsigned char *, (1+ np_PaX)))[4]; |
3970 | 0 | unsigned bits = get_te32(p4); |
3971 | 0 | bits &= ~PAX_MPROTECT; |
3972 | 0 | bits |= PAX_NOMPROTECT; |
3973 | 0 | set_te32(ACC_UNCONST_CAST(unsigned char *, p4), bits); |
3974 | |
|
3975 | 0 | sz_elf_hdrs += sz_PaX + sizeof(*phdr); |
3976 | 0 | note_offset += sz_PaX; |
3977 | 0 | ++phdr; |
3978 | 0 | } |
3979 | 0 | set_te32(&h2->phdr[C_TEXT].p_filesz, note_offset); |
3980 | 0 | h2->phdr[C_TEXT].p_memsz = h2->phdr[C_TEXT].p_filesz; |
3981 | |
|
3982 | 0 | if (ph.format==getFormat()) { |
3983 | 0 | set_te16(&h2->ehdr.e_phnum, !!sz_NetBSD + !!sz_PaX + |
3984 | 0 | get_te16(&h2->ehdr.e_phnum)); |
3985 | 0 | fo->seek(0, SEEK_SET); |
3986 | 0 | fo->rewrite(h2, sizeof(*h2) - sizeof(h2->linfo)); |
3987 | | |
3988 | | // The 'if' guards on these two calls to memcpy are required |
3989 | | // because the C Standard Committee did not debug the Standard |
3990 | | // before publishing. An empty region (0==size) must nevertheless |
3991 | | // have a valid (non-nullptr) pointer. |
3992 | 0 | if (sz_NetBSD) memcpy(&((char *)phdr)[0], np_NetBSD, sz_NetBSD); |
3993 | 0 | if (sz_PaX) memcpy(&((char *)phdr)[sz_NetBSD], np_PaX, sz_PaX); |
3994 | |
|
3995 | 0 | fo->write(&elfout.phdr[C_NOTE], |
3996 | 0 | &((char *)phdr)[sz_PaX + sz_NetBSD] - (char *)&elfout.phdr[C_NOTE]); |
3997 | |
|
3998 | 0 | l_info foo; memset(&foo, 0, sizeof(foo)); |
3999 | 0 | fo->rewrite(&foo, sizeof(foo)); |
4000 | 0 | } |
4001 | 0 | else { |
4002 | 0 | assert(false); // unknown ph.format, PackLinuxElf32 |
4003 | 0 | } |
4004 | 0 | } |
4005 | | |
4006 | | void |
4007 | | PackOpenBSDElf32x86::generateElfHdr( |
4008 | | OutputFile *fo, |
4009 | | void const *proto, |
4010 | | unsigned const brka |
4011 | | ) |
4012 | 0 | { |
4013 | 0 | cprElfHdr3 *const h3 = (cprElfHdr3 *)(void *)&elfout; |
4014 | 0 | memcpy(h3, proto, sizeof(*h3)); // reads beyond, but OK |
4015 | 0 | h3->ehdr.e_ident[Elf32_Ehdr::EI_OSABI] = ei_osabi; |
4016 | 0 | assert(2==get_te16(&h3->ehdr.e_phnum)); |
4017 | 0 | set_te16(&h3->ehdr.e_phnum, 3); |
4018 | |
|
4019 | 0 | assert(get_te32(&h3->ehdr.e_phoff) == sizeof(Elf32_Ehdr)); |
4020 | 0 | h3->ehdr.e_shoff = 0; |
4021 | 0 | assert(get_te16(&h3->ehdr.e_ehsize) == sizeof(Elf32_Ehdr)); |
4022 | 0 | assert(get_te16(&h3->ehdr.e_phentsize) == sizeof(Elf32_Phdr)); |
4023 | 0 | set_te16(&h3->ehdr.e_shentsize, sizeof(Elf32_Shdr)); // libbfd-2.41-38.fc40 |
4024 | 0 | h3->ehdr.e_shnum = 0; |
4025 | 0 | h3->ehdr.e_shstrndx = 0; |
4026 | |
|
4027 | 0 | struct { |
4028 | 0 | Elf32_Nhdr nhdr; |
4029 | 0 | char name[8]; |
4030 | 0 | unsigned body; |
4031 | 0 | } elfnote; |
4032 | |
|
4033 | 0 | unsigned const note_offset = sizeof(*h3) - sizeof(linfo); |
4034 | 0 | sz_elf_hdrs = sizeof(elfnote) + note_offset; |
4035 | |
|
4036 | 0 | set_te32(&h3->phdr[C_NOTE].p_type, PT_NOTE32); |
4037 | 0 | set_te32(&h3->phdr[C_NOTE].p_offset, note_offset); |
4038 | 0 | set_te32(&h3->phdr[C_NOTE].p_vaddr, note_offset); |
4039 | 0 | set_te32(&h3->phdr[C_NOTE].p_paddr, note_offset); |
4040 | 0 | set_te32(&h3->phdr[C_NOTE].p_filesz, sizeof(elfnote)); |
4041 | 0 | set_te32(&h3->phdr[C_NOTE].p_memsz, sizeof(elfnote)); |
4042 | 0 | set_te32(&h3->phdr[C_NOTE].p_flags, Elf32_Phdr::PF_R); |
4043 | 0 | set_te32(&h3->phdr[C_NOTE].p_align, 4); |
4044 | | |
4045 | | // Q: Same as this->note_body[0 .. this->note_size-1] ? |
4046 | 0 | set_te32(&elfnote.nhdr.namesz, 8); |
4047 | 0 | set_te32(&elfnote.nhdr.descsz, OPENBSD_DESCSZ); |
4048 | 0 | set_te32(&elfnote.nhdr.type, NHDR_OPENBSD_TAG); |
4049 | 0 | memcpy(elfnote.name, "OpenBSD", sizeof(elfnote.name)); |
4050 | 0 | elfnote.body = 0; |
4051 | |
|
4052 | 0 | set_te32(&h3->phdr[C_TEXT].p_filesz, sz_elf_hdrs); |
4053 | 0 | h3->phdr[C_TEXT].p_memsz = h3->phdr[C_TEXT].p_filesz; |
4054 | |
|
4055 | 0 | unsigned const brkb = brka | ((0==(~page_mask & brka)) ? 0x20 : 0); |
4056 | 0 | set_te32(&h3->phdr[C_BASE].p_type, PT_LOAD); // be sure |
4057 | 0 | set_te32(&h3->phdr[C_BASE].p_offset, ~page_mask & brkb); |
4058 | 0 | set_te32(&h3->phdr[C_BASE].p_vaddr, brkb); |
4059 | 0 | set_te32(&h3->phdr[C_BASE].p_paddr, brkb); |
4060 | 0 | h3->phdr[C_BASE].p_filesz = 0; |
4061 | | // Too many kernels have bugs when 0==.p_memsz |
4062 | 0 | set_te32(&h3->phdr[C_BASE].p_memsz, 1); |
4063 | 0 | set_te32(&h3->phdr[C_BASE].p_flags, Elf32_Phdr::PF_R | Elf32_Phdr::PF_W); |
4064 | |
|
4065 | 0 | if (ph.format==getFormat()) { |
4066 | 0 | memset(&h3->linfo, 0, sizeof(h3->linfo)); |
4067 | 0 | fo->write(h3, sizeof(*h3) - sizeof(h3->linfo)); |
4068 | 0 | fo->write(&elfnote, sizeof(elfnote)); |
4069 | 0 | fo->write(&h3->linfo, sizeof(h3->linfo)); |
4070 | 0 | } |
4071 | 0 | else { |
4072 | 0 | assert(false); // unknown ph.format, PackLinuxElf32 |
4073 | 0 | } |
4074 | 0 | } |
4075 | | |
4076 | | void |
4077 | | PackLinuxElf64::generateElfHdr( |
4078 | | OutputFile *fo, |
4079 | | void const *proto, |
4080 | | unsigned const brka |
4081 | | ) |
4082 | 0 | { |
4083 | 0 | cprElfHdr2 *const h2 = (cprElfHdr2 *)(void *)&elfout; |
4084 | 0 | cprElfHdr3 *const h3 = (cprElfHdr3 *)(void *)&elfout; |
4085 | 0 | h3->ehdr = ((cprElfHdr3 const *)proto)->ehdr; |
4086 | 0 | if (Elf64_Ehdr::ET_REL == get_te16(&h3->ehdr.e_type)) { |
4087 | 0 | set_te64(&h3->ehdr.e_phoff, sizeof(Elf64_Ehdr)); |
4088 | 0 | set_te16(&h3->ehdr.e_ehsize,sizeof(Elf64_Ehdr)); |
4089 | 0 | set_te16(&h3->ehdr.e_phentsize, sizeof(Elf64_Phdr)); |
4090 | 0 | set_te16(&h3->ehdr.e_phnum, 2); |
4091 | 0 | memset(&h3->phdr[C_BASE], 0, sizeof(h3->phdr[C_BASE])); |
4092 | 0 | memset(&h3->phdr[C_TEXT], 0, sizeof(h3->phdr[C_TEXT])); |
4093 | 0 | memset(&h3->phdr[2 ], 0, sizeof(h3->phdr[2 ])); |
4094 | 0 | set_te32(&h3->phdr[C_BASE].p_flags, 0); |
4095 | 0 | set_te32(&h3->phdr[C_TEXT].p_flags, Elf64_Phdr::PF_X| Elf64_Phdr::PF_R); |
4096 | 0 | } |
4097 | 0 | else { |
4098 | 0 | h3->phdr[C_BASE] = ((cprElfHdr3 const *)proto)->phdr[1]; // .data; .p_align |
4099 | 0 | h3->phdr[C_TEXT] = ((cprElfHdr3 const *)proto)->phdr[0]; // .text |
4100 | 0 | } |
4101 | 0 | memset(&h3->linfo, 0, sizeof(h3->linfo)); |
4102 | |
|
4103 | 0 | h3->ehdr.e_type = ehdri.e_type; // ET_EXEC vs ET_DYN (gcc -pie -fPIC) |
4104 | 0 | h3->ehdr.e_ident[Elf64_Ehdr::EI_OSABI] = ei_osabi; |
4105 | 0 | if (Elf64_Ehdr::ELFOSABI_LINUX == ei_osabi // proper |
4106 | 0 | && Elf64_Ehdr::ELFOSABI_NONE == ehdri.e_ident[Elf64_Ehdr::EI_OSABI] // sloppy |
4107 | 0 | ) { // propagate sloppiness so that decompression does not complain |
4108 | 0 | h3->ehdr.e_ident[Elf64_Ehdr::EI_OSABI] = ehdri.e_ident[Elf64_Ehdr::EI_OSABI]; |
4109 | 0 | } |
4110 | 0 | if (Elf64_Ehdr::EM_PPC64 == get_te16(&ehdri.e_machine)) { |
4111 | 0 | h3->ehdr.e_flags = ehdri.e_flags; // "0x1, abiv1" vs "0x2, abiv2" |
4112 | 0 | } |
4113 | |
|
4114 | 0 | assert(get_te64(&h2->ehdr.e_phoff) == sizeof(Elf64_Ehdr)); |
4115 | 0 | assert(get_te16(&h2->ehdr.e_ehsize) == sizeof(Elf64_Ehdr)); |
4116 | 0 | assert(get_te16(&h2->ehdr.e_phentsize) == sizeof(Elf64_Phdr)); |
4117 | | |
4118 | 0 | h2->ehdr.e_shoff = 0; |
4119 | 0 | set_te16(&h2->ehdr.e_shentsize, sizeof(Elf64_Shdr)); // libbfd-2.41-38.fc40 |
4120 | 0 | if (o_elf_shnum) { |
4121 | 0 | h2->ehdr.e_shnum = o_elf_shnum; |
4122 | 0 | h2->ehdr.e_shstrndx = o_elf_shnum - 1; |
4123 | 0 | } |
4124 | 0 | else { |
4125 | | // https://bugzilla.redhat.com/show_bug.cgi?id=2131609 |
4126 | | // 0==.e_shnum is a special case for libbfd |
4127 | | // that requires 0==.e_shentsize in order to force "no Shdrs" |
4128 | | // But qemu 8.2.9 with libbfd-2.41-38.fc40 says EXEC format error |
4129 | | // and uses 0==.e_shoff instead. |
4130 | | // h2->ehdr.e_shentsize = 0; |
4131 | 0 | h2->ehdr.e_shnum = 0; |
4132 | 0 | h2->ehdr.e_shstrndx = 0; |
4133 | 0 | } |
4134 | |
|
4135 | 0 | unsigned const phnum_i = get_te16(&h2->ehdr.e_phnum); |
4136 | 0 | unsigned phnum_o = 2 + n_phdrx; // C_BASE, C_TEXT |
4137 | 0 | set_te16(&h2->ehdr.e_phnum, phnum_o); |
4138 | 0 | o_binfo = sizeof(Elf64_Ehdr) + sizeof(Elf64_Phdr)*phnum_o + sizeof(l_info) + sizeof(p_info); |
4139 | 0 | set_te64(&h2->phdr[C_TEXT].p_filesz, sizeof(*h2)); // + identsize; |
4140 | 0 | h2->phdr[C_TEXT].p_memsz = h2->phdr[C_TEXT].p_filesz; |
4141 | 0 | set_te32(&h2->phdr[C_TEXT].p_type, PT_LOAD); // be sure |
4142 | |
|
4143 | 0 | for (unsigned j=0; j < phnum_i; ++j) { |
4144 | 0 | if (is_LOAD(&h3->phdr[j])) { |
4145 | 0 | set_te64( &h3->phdr[j].p_align, page_size); |
4146 | 0 | } |
4147 | 0 | } |
4148 | | |
4149 | | // Info for OS kernel to set the brk() |
4150 | 0 | if (brka) { |
4151 | | // linux-2.6.14 binfmt_elf.c: SIGKILL if (0==.p_memsz) on a page boundary |
4152 | 0 | upx_uint64_t lo_va_user(~(upx_uint64_t)0); // infinity |
4153 | 0 | for (int j= e_phnum; --j>=0; ) { |
4154 | 0 | if (is_LOAD(&phdri[j])) { |
4155 | 0 | upx_uint64_t const vaddr = get_te64(&phdri[j].p_vaddr); |
4156 | 0 | lo_va_user = umin(lo_va_user, vaddr); |
4157 | 0 | } |
4158 | 0 | } |
4159 | 0 | set_te64( &h2->phdr[C_BASE].p_vaddr, lo_va_user); |
4160 | 0 | h2->phdr[C_BASE].p_paddr = h2->phdr[C_BASE].p_vaddr; |
4161 | 0 | h2->phdr[C_TEXT].p_vaddr = h2->phdr[C_BASE].p_vaddr; |
4162 | 0 | h2->phdr[C_TEXT].p_paddr = h2->phdr[C_BASE].p_vaddr; |
4163 | 0 | set_te32(&h2->phdr[C_BASE].p_type, PT_LOAD); // be sure |
4164 | 0 | h2->phdr[C_BASE].p_offset = 0; |
4165 | 0 | h2->phdr[C_BASE].p_filesz = 0; |
4166 | | // .p_memsz = brka; temporary until sz_pack2 |
4167 | 0 | set_te64(&h2->phdr[C_BASE].p_memsz, brka - lo_va_user); |
4168 | 0 | set_te32(&h2->phdr[C_BASE].p_flags, Elf64_Phdr::PF_R | Elf64_Phdr::PF_W); |
4169 | 0 | } |
4170 | 0 | set_te64(&h3->phdr[C_BASE].p_align, page_size); |
4171 | 0 | set_te64(&h3->phdr[C_TEXT].p_align, page_size); |
4172 | 0 | set_te32(&h2->phdr[C_TEXT].p_flags, ~Elf64_Phdr::PF_W & get_te32(&h2->phdr[C_TEXT].p_flags)); |
4173 | 0 | fo->write(h2, sizeof(Elf64_Ehdr) + 2* sizeof(Elf64_Phdr)); // C_BASE, C_TEXT |
4174 | |
|
4175 | 0 | u64_t const zero_pad = 0; |
4176 | 0 | unsigned uva0 = get_te64(&h2->phdr[C_TEXT].p_vaddr); |
4177 | 0 | unsigned off_o = 0; |
4178 | 0 | for (unsigned phase = 0; phase < 2; ++phase) { // 0: Phdrs; 1: bodies |
4179 | 0 | off_o = sizeof(Elf64_Ehdr) + phnum_o * sizeof(Elf64_Phdr); |
4180 | 0 | for (unsigned j = 0; j < n_phdrx; ++j) { |
4181 | 0 | Elf64_Phdr phtmp = *phdrx[j]; |
4182 | 0 | phtmp.p_vaddr = phtmp.p_paddr = 0; |
4183 | 0 | u64_t const off_i = get_te64(&phtmp.p_offset); |
4184 | 0 | u64_t const align = get_te64(&phtmp.p_align); |
4185 | 0 | u64_t const filesz = get_te64(&phtmp.p_filesz); |
4186 | 0 | unsigned pad = 0; |
4187 | 0 | if (filesz && align && is_pow2(align)) { |
4188 | 0 | unsigned alm1 = -1 + umin(8u, (unsigned)align); |
4189 | 0 | pad = alm1 & (0u - off_o); |
4190 | 0 | off_o += pad; |
4191 | 0 | set_te64(&phtmp.p_vaddr, off_o + uva0); phtmp.p_paddr = phtmp.p_vaddr; |
4192 | 0 | } |
4193 | 0 | if (0==phase) { |
4194 | 0 | set_te64(&phtmp.p_offset, (filesz ? off_o : 0)); |
4195 | 0 | fo->write(&phtmp, sizeof(phtmp)); // Phdr |
4196 | 0 | } |
4197 | 0 | if (1==phase) { |
4198 | 0 | if (pad) fo->write(&zero_pad, pad); |
4199 | 0 | if (filesz) fo->write(&file_image[off_i], filesz); // body |
4200 | 0 | } |
4201 | 0 | off_o += filesz; |
4202 | 0 | } |
4203 | 0 | } |
4204 | 0 | off_o = fpad4(fo, off_o); |
4205 | 0 | sz_phdrx = off_o - (sizeof(Elf64_Ehdr) + phnum_o * sizeof(Elf64_Phdr)); |
4206 | 0 | set_te64(&h2->phdr[C_BASE].p_filesz, off_o); |
4207 | |
|
4208 | 0 | sz_elf_hdrs = sizeof(Elf64_Ehdr) + phnum_o * sizeof(Elf64_Phdr) + sz_phdrx; |
4209 | 0 | overlay_offset = sz_elf_hdrs + sizeof(l_info); |
4210 | 0 | o_binfo = sz_elf_hdrs + sizeof(l_info) + sizeof(p_info); |
4211 | |
|
4212 | 0 | l_info linfo2; memset(&linfo2, 0, sizeof(linfo2)); |
4213 | 0 | fo->write(&linfo2, sizeof(linfo2)); |
4214 | 0 | } |
4215 | | |
4216 | | // Android shlib has ABS symbols that actually are relative. |
4217 | | static char const abs_symbol_names[][14] = { |
4218 | | "__bss_end__" |
4219 | | , "_bss_end__" |
4220 | | , "__bss_start" |
4221 | | , "__bss_start__" |
4222 | | , "_edata" |
4223 | | , "_end" |
4224 | | , "__end__" |
4225 | | , "" |
4226 | | }; |
4227 | | |
4228 | | int |
4229 | | PackLinuxElf32::adjABS(Elf32_Sym *sym, unsigned delta) |
4230 | 0 | { |
4231 | 0 | unsigned st_name = get_te32(&sym->st_name); |
4232 | 0 | for (int j = 0; abs_symbol_names[j][0]; ++j) { |
4233 | 0 | if (!strcmp(abs_symbol_names[j], get_str_name(st_name, (unsigned)-1))) { |
4234 | 0 | sym->st_value += delta; |
4235 | 0 | return 1; |
4236 | 0 | } |
4237 | 0 | } |
4238 | 0 | return 0; |
4239 | 0 | } |
4240 | | |
4241 | | int |
4242 | | PackLinuxElf64::adjABS(Elf64_Sym *sym, unsigned long delta) |
4243 | 0 | { |
4244 | 0 | unsigned st_name = get_te32(&sym->st_name); |
4245 | 0 | for (int j = 0; abs_symbol_names[j][0]; ++j) { |
4246 | 0 | if (!strcmp(abs_symbol_names[j], get_str_name(st_name, (unsigned)-1))) { |
4247 | 0 | sym->st_value += delta; |
4248 | 0 | return 1; |
4249 | 0 | } |
4250 | 0 | } |
4251 | 0 | return 0; |
4252 | 0 | } |
4253 | | |
4254 | | void PackLinuxElf32::pack1(OutputFile * /*fo*/, Filter &ft) |
4255 | 0 | { |
4256 | 0 | fi->seek(0, SEEK_SET); |
4257 | 0 | fi->readx(&ehdri, sizeof(ehdri)); |
4258 | 0 | assert(e_phoff == sizeof(Elf32_Ehdr)); // checked by canPack() |
4259 | 0 | sz_phdrs = e_phnum * get_te16(&ehdri.e_phentsize); |
4260 | | |
4261 | | // We compress separate pieces (usually each PT_LOAD, plus the gaps in the file |
4262 | | // that are not covered by any PT_LOAD), but currently at run time there can be |
4263 | | // only one decompressor method. |
4264 | | // Therefore we must plan ahead because Packer::compressWithFilters tries |
4265 | | // to find the smallest result among the available methods, for one piece only. |
4266 | | // In the future we may allow more than one decompression method at run time. |
4267 | | // For now we must choose only one, and force PackUnix::packExtent |
4268 | | // (==> compressWithFilters) to use it. |
4269 | 0 | int nfilters = 0; |
4270 | 0 | { |
4271 | 0 | int const *fp = getFilters(); |
4272 | 0 | while (FT_END != *fp++) { |
4273 | 0 | ++nfilters; |
4274 | 0 | } |
4275 | 0 | } |
4276 | 0 | { |
4277 | 0 | int npieces = 1; // tail after highest PT_LOAD |
4278 | 0 | Elf32_Phdr *phdr = phdri; |
4279 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
4280 | 0 | if (is_LOAD(phdr)) { |
4281 | 0 | unsigned const flags = get_te32(&phdr->p_flags); |
4282 | 0 | unsigned offset = get_te32(&phdr->p_offset); |
4283 | 0 | if (!xct_off // not shlib |
4284 | | // new-style shlib: PT_LOAD[0] has symbol table |
4285 | | // which must not be compressed, but also lacks PF_X |
4286 | 0 | || (Elf32_Phdr::PF_X & flags) |
4287 | | // Read-only, non-first PT_LOAD is _assumed_ to be compressible |
4288 | 0 | || (!(Elf32_Phdr::PF_W & flags) && 0!=offset)) |
4289 | 0 | { |
4290 | 0 | ++npieces; // will attempt compression of this PT_LOAD |
4291 | 0 | } |
4292 | 0 | } |
4293 | 0 | } |
4294 | 0 | uip->ui_total_passes += npieces; |
4295 | 0 | } |
4296 | 0 | int methods[256]; |
4297 | 0 | unsigned nmethods = prepareMethods(methods, ph.method, getCompressionMethods(M_ALL, ph.level)); |
4298 | 0 | if (1 < nmethods) { // Many are available, but we must choose only one |
4299 | 0 | uip->ui_total_passes += 1; // the batch for output |
4300 | 0 | uip->ui_total_passes *= nmethods * (1+ nfilters); // finding smallest total |
4301 | 0 | PackHeader orig_ph = ph; |
4302 | 0 | Filter orig_ft = ft; |
4303 | 0 | unsigned max_offset = 0; |
4304 | 0 | unsigned sz_best= ~0u; |
4305 | 0 | int method_best = 0; |
4306 | 0 | for (unsigned k = 0; k < nmethods; ++k) { // FIXME: parallelize; cost: working space |
4307 | 0 | unsigned sz_this = 0; |
4308 | 0 | Elf32_Phdr *phdr = phdri; |
4309 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
4310 | 0 | if (is_LOAD(phdr)) { |
4311 | 0 | unsigned const flags = get_te32(&phdr->p_flags); |
4312 | 0 | unsigned offset = get_te32(&phdr->p_offset); |
4313 | 0 | unsigned filesz = get_te32(&phdr->p_filesz); |
4314 | 0 | max_offset = UPX_MAX(max_offset, filesz + offset); |
4315 | 0 | if (!xct_off // not shlib |
4316 | | // new-style shlib: PT_LOAD[0] has symbol table |
4317 | | // which must not be compressed, but also lacks PF_X |
4318 | 0 | || (Elf32_Phdr::PF_X & flags) |
4319 | | // Read-only, non-first PT_LOAD is _assumed_ to be compressible |
4320 | 0 | || (!(Elf32_Phdr::PF_W & flags) && 0!=offset)) |
4321 | 0 | { |
4322 | 0 | if (xct_off && 0==offset) { // old-style shlib |
4323 | 0 | offset = xct_off; |
4324 | 0 | filesz -= xct_off; |
4325 | 0 | } |
4326 | 0 | fi->seek(offset, SEEK_SET); |
4327 | 0 | fi->readx(ibuf, filesz); |
4328 | 0 | ft = orig_ft; |
4329 | 0 | ph = orig_ph; |
4330 | 0 | ph.set_method(ph_force_method(methods[k]), offset); |
4331 | 0 | ph.u_len = filesz; |
4332 | 0 | compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true); |
4333 | 0 | sz_this += ph.c_len; |
4334 | 0 | } |
4335 | 0 | } |
4336 | 0 | } |
4337 | 0 | unsigned const sz_tail = file_size - max_offset; // debuginfo, etc. |
4338 | 0 | if (sz_tail) { |
4339 | 0 | fi->seek(max_offset, SEEK_SET); |
4340 | 0 | fi->readx(ibuf, sz_tail); |
4341 | 0 | ft = orig_ft; |
4342 | 0 | ph = orig_ph; |
4343 | 0 | ph.set_method(ph_force_method(methods[k])); |
4344 | 0 | ph.u_len = sz_tail; |
4345 | 0 | compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true); |
4346 | 0 | sz_this += ph.c_len; |
4347 | 0 | } |
4348 | | // FIXME: loader size also depends on method |
4349 | 0 | if (sz_best > sz_this) { |
4350 | 0 | sz_best = sz_this; |
4351 | 0 | method_best = methods[k]; |
4352 | 0 | } |
4353 | 0 | } |
4354 | 0 | ft = orig_ft; |
4355 | 0 | ph = orig_ph; |
4356 | 0 | ph.set_method(ph_force_method(method_best)); |
4357 | 0 | } |
4358 | |
|
4359 | 0 | Elf32_Phdr *phdr = phdri; |
4360 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
4361 | 0 | unsigned const type = get_te32(&phdr->p_type); |
4362 | 0 | if (PT_GNU_STACK32 == type || PT_NOTE32 == type) { |
4363 | 0 | add_phdrx(phdr); // PT_GNU_STACK32, PT_NOTE32 |
4364 | 0 | } |
4365 | 0 | if (PT_LOAD == type) { |
4366 | 0 | unsigned x = get_te32(&phdr->p_align) >> lg2_page; |
4367 | 0 | while (x>>=1) { |
4368 | 0 | ++lg2_page; |
4369 | 0 | } |
4370 | 0 | } |
4371 | 0 | if (PT_GNU_RELRO32 == type |
4372 | 0 | && 16 < lg2_page) { |
4373 | | // x86* allows 4K, 2M, 1G |
4374 | | // arm32 and arm64 both allow 4K, 16K, 64K; Apple Silicon uses 16K |
4375 | | // Oracle 5.4.17-2136.314.6.2.el8uek.aarch64 demands 64K |
4376 | | // PowerPC and PowerPC64 has 4K, 64K, 1M (?), 16M (?) |
4377 | | // MIPS allows any power of 2 from 4K through 64K |
4378 | | |
4379 | | // If 64K < .p_align then we assume that 4K is also accepted. |
4380 | | // .p_align can be like 2M, which is a huge over-estimate. |
4381 | | // RELRO ends on a page boundary: usually close to actual page_size |
4382 | 0 | unsigned offset = get_te32(&phdr->p_offset); |
4383 | 0 | unsigned filesz = get_te32(&phdr->p_filesz); |
4384 | 0 | if (!(0xfff & (filesz + offset))) { // a 4KiB boundary |
4385 | 0 | unsigned b = 12; |
4386 | 0 | while (!(~(~0u << b) & (filesz + offset))) { |
4387 | 0 | ++b; |
4388 | 0 | } |
4389 | 0 | lg2_page = umin(lg2_page, -1+ b); |
4390 | 0 | } |
4391 | 0 | } |
4392 | 0 | } |
4393 | 0 | page_size = 1u <<lg2_page; |
4394 | 0 | page_mask = ~0ull<<lg2_page; |
4395 | |
|
4396 | 0 | progid = 0; // getRandomId(); not useful, so do not clutter |
4397 | 0 | sz_elf_hdrs = sizeof(ehdri) + sz_phdrs; |
4398 | | |
4399 | | // only execute if option present |
4400 | 0 | if (opt->o_unix.preserve_build_id) { |
4401 | | // set this so we can use elf_find_section_name |
4402 | 0 | e_shnum = get_te16(&ehdri.e_shnum); |
4403 | 0 | if (!shdri) { |
4404 | 0 | mb_shdr.alloc(e_shnum * sizeof(Elf32_Shdr)); |
4405 | 0 | shdri = (Elf32_Shdr *)mb_shdr.getVoidPtr(); |
4406 | 0 | e_shoff = get_te32(&ehdri.e_shoff); |
4407 | 0 | fi->seek(e_shoff, SEEK_SET); |
4408 | 0 | fi->readx(shdri, e_shnum * sizeof(Elf32_Shdr)); |
4409 | 0 | } |
4410 | | //set the shstrtab |
4411 | 0 | sec_strndx = &shdri[get_te16(&ehdri.e_shstrndx)]; |
4412 | |
|
4413 | 0 | upx_uint32_t sh_size = get_te32(&sec_strndx->sh_size); |
4414 | 0 | mb_shstrtab.alloc(sh_size); shstrtab = (char *)mb_shstrtab.getVoidPtr(); |
4415 | 0 | fi->seek(0,SEEK_SET); |
4416 | 0 | fi->seek(sec_strndx->sh_offset,SEEK_SET); |
4417 | 0 | fi->readx(mb_shstrtab, sh_size); |
4418 | |
|
4419 | 0 | Elf32_Shdr const *buildid = elf_find_section_name(".note.gnu.build-id"); |
4420 | 0 | if (buildid) { |
4421 | 0 | unsigned bid_sh_size = get_te32(&buildid->sh_size); |
4422 | 0 | buildid_data.alloc(bid_sh_size); |
4423 | 0 | buildid_data.clear(); |
4424 | 0 | fi->seek(0,SEEK_SET); |
4425 | 0 | fi->seek(buildid->sh_offset,SEEK_SET); |
4426 | 0 | fi->readx((void *)buildid_data, bid_sh_size); |
4427 | |
|
4428 | 0 | o_elf_shnum = 3; |
4429 | 0 | memset(&shdrout,0,sizeof(shdrout)); |
4430 | | |
4431 | | //setup the build-id |
4432 | 0 | memcpy(&shdrout.shdr[1], buildid, sizeof(shdrout.shdr[1])); |
4433 | 0 | set_te32(&shdrout.shdr[1].sh_name, 1); |
4434 | | |
4435 | | //setup the shstrtab |
4436 | 0 | memcpy(&shdrout.shdr[2], sec_strndx, sizeof(shdrout.shdr[2])); |
4437 | 0 | set_te32(&shdrout.shdr[2].sh_name, 20); |
4438 | 0 | set_te32(&shdrout.shdr[2].sh_size, 29); //size of our static shstrtab |
4439 | 0 | } |
4440 | 0 | } |
4441 | 0 | } |
4442 | | |
4443 | | void PackLinuxElf32x86::pack1(OutputFile *fo, Filter &ft) |
4444 | 0 | { |
4445 | 0 | super::pack1(fo, ft); |
4446 | 0 | if (0!=xct_off) // shared library |
4447 | 0 | return; |
4448 | 0 | generateElfHdr(fo, stub_i386_linux_elf_fold, getbrk(phdri, e_phnum) ); |
4449 | 0 | } |
4450 | | |
4451 | | void PackBSDElf32x86::pack1(OutputFile *fo, Filter &ft) |
4452 | 0 | { |
4453 | 0 | super::pack1(fo, ft); |
4454 | 0 | if (0!=xct_off) // shared library |
4455 | 0 | return; |
4456 | 0 | generateElfHdr(fo, stub_i386_bsd_elf_fold, getbrk(phdri, e_phnum) ); |
4457 | 0 | } |
4458 | | |
4459 | | void PackLinuxElf32armLe::pack1(OutputFile *fo, Filter &ft) |
4460 | 0 | { |
4461 | 0 | super::pack1(fo, ft); |
4462 | 0 | if (0!=xct_off) // shared library |
4463 | 0 | return; |
4464 | 0 | unsigned const e_flags = get_te32(&ehdri.e_flags); |
4465 | 0 | cprElfHdr3 h3; |
4466 | 0 | if (Elf32_Ehdr::ELFOSABI_LINUX==ei_osabi) { |
4467 | 0 | memcpy(&h3, stub_arm_v5a_linux_elf_fold, sizeof(Elf32_Ehdr) + 2*sizeof(Elf32_Phdr)); |
4468 | |
|
4469 | 0 | h3.ehdr.e_ident[Elf32_Ehdr::EI_ABIVERSION] = e_flags>>24; |
4470 | 0 | } |
4471 | 0 | else { |
4472 | 0 | memcpy(&h3, stub_arm_v4a_linux_elf_fold, sizeof(Elf32_Ehdr) + 2*sizeof(Elf32_Phdr)); |
4473 | 0 | } |
4474 | | // Fighting over .e_ident[EI_ABIVERSION]: Debian armhf is latest culprit. |
4475 | | // So copy from input to output; but see PackLinuxElf32::generateElfHdr |
4476 | 0 | memcpy(&h3.ehdr.e_ident[0], &ehdri.e_ident[0], sizeof(ehdri.e_ident)); |
4477 | 0 | set_te32(&h3.ehdr.e_flags, e_flags); |
4478 | 0 | generateElfHdr(fo, &h3, getbrk(phdri, e_phnum) ); |
4479 | 0 | } |
4480 | | |
4481 | | void PackLinuxElf32armBe::pack1(OutputFile *fo, Filter &ft) |
4482 | 0 | { |
4483 | 0 | super::pack1(fo, ft); |
4484 | 0 | if (0!=xct_off) // shared library |
4485 | 0 | return; |
4486 | 0 | unsigned const e_flags = get_te32(&ehdri.e_flags); |
4487 | 0 | cprElfHdr3 h3; |
4488 | 0 | memcpy(&h3, stub_armeb_v4a_linux_elf_fold, sizeof(Elf32_Ehdr) + 2*sizeof(Elf32_Phdr)); |
4489 | 0 | set_te32(&h3.ehdr.e_flags, e_flags); |
4490 | 0 | generateElfHdr(fo, &h3, getbrk(phdri, e_phnum) ); |
4491 | 0 | } |
4492 | | |
4493 | | void PackLinuxElf32mipsel::pack1(OutputFile *fo, Filter &ft) |
4494 | 0 | { |
4495 | 0 | super::pack1(fo, ft); |
4496 | 0 | if (0!=xct_off) // shared library |
4497 | 0 | return; |
4498 | 0 | cprElfHdr3 h3; |
4499 | 0 | memcpy(&h3, stub_mipsel_r3000_linux_elf_fold, sizeof(Elf32_Ehdr) + 2*sizeof(Elf32_Phdr)); |
4500 | 0 | generateElfHdr(fo, &h3, getbrk(phdri, e_phnum) ); |
4501 | 0 | } |
4502 | | |
4503 | | void PackLinuxElf32mipseb::pack1(OutputFile *fo, Filter &ft) |
4504 | 0 | { |
4505 | 0 | super::pack1(fo, ft); |
4506 | 0 | if (0!=xct_off) // shared library |
4507 | 0 | return; |
4508 | 0 | cprElfHdr3 h3; |
4509 | 0 | memcpy(&h3, stub_mips_r3000_linux_elf_fold, sizeof(Elf32_Ehdr) + 2*sizeof(Elf32_Phdr)); |
4510 | 0 | generateElfHdr(fo, &h3, getbrk(phdri, e_phnum) ); |
4511 | 0 | } |
4512 | | |
4513 | | void PackLinuxElf32ppc::pack1(OutputFile *fo, Filter &ft) |
4514 | 0 | { |
4515 | 0 | super::pack1(fo, ft); |
4516 | 0 | if (0!=xct_off) // shared library |
4517 | 0 | return; |
4518 | 0 | generateElfHdr(fo, stub_powerpc_linux_elf_fold, getbrk(phdri, e_phnum) ); |
4519 | 0 | } |
4520 | | |
4521 | | void PackLinuxElf64ppcle::pack1(OutputFile *fo, Filter &ft) |
4522 | 0 | { |
4523 | 0 | super::pack1(fo, ft); |
4524 | 0 | if (0!=xct_off) // shared library |
4525 | 0 | return; |
4526 | 0 | generateElfHdr(fo, stub_powerpc64le_linux_elf_fold, getbrk(phdri, e_phnum) ); |
4527 | 0 | } |
4528 | | |
4529 | | void PackLinuxElf64ppc::pack1(OutputFile *fo, Filter &ft) |
4530 | 0 | { |
4531 | 0 | super::pack1(fo, ft); |
4532 | 0 | if (0!=xct_off) // shared library |
4533 | 0 | return; |
4534 | 0 | generateElfHdr(fo, stub_powerpc64_linux_elf_fold, getbrk(phdri, e_phnum) ); |
4535 | 0 | } |
4536 | | |
4537 | | void PackLinuxElf64::asl_pack2_Shdrs(OutputFile *fo, unsigned pre_xct_top) |
4538 | 0 | { |
4539 | 0 | if (!fo) { |
4540 | 0 | return; |
4541 | 0 | } |
4542 | | // In order to pacify the runtime linker on Android "O" ("Oreo"), |
4543 | | // we will splice-in a 4KiB page that contains an "extra" copy |
4544 | | // of the Shdr, any PT_NOTE above xct_off, and shstrtab. |
4545 | | // File order: Ehdr, Phdr[], section contents below xct_off, |
4546 | | // Shdr_copy[], PT_NOTEs.hi, shstrtab. |
4547 | 0 | if (is_asl) |
4548 | 0 | xct_va += asl_delta; |
4549 | | //xct_off += asl_delta; // not until ::pack3() |
4550 | |
|
4551 | 0 | total_in = pre_xct_top; |
4552 | | |
4553 | | // Relocate PT_DYNAMIC (in PT_LOAD with PF_W) |
4554 | 0 | Elf64_Dyn *dyn = const_cast<Elf64_Dyn *>(dynseg); |
4555 | 0 | for (; dyn->d_tag; ++dyn) { |
4556 | 0 | upx_uint64_t d_tag = get_te64(&dyn->d_tag); |
4557 | 0 | if (Elf64_Dyn::DT_FINI == d_tag |
4558 | 0 | || Elf64_Dyn::DT_FINI_ARRAY == d_tag |
4559 | 0 | || Elf64_Dyn::DT_INIT_ARRAY == d_tag |
4560 | 0 | || Elf64_Dyn::DT_PREINIT_ARRAY == d_tag |
4561 | 0 | || Elf64_Dyn::DT_PLTGOT == d_tag) { |
4562 | 0 | upx_uint64_t d_val = get_te64(&dyn->d_val); |
4563 | 0 | set_te64(&dyn->d_val, asl_delta + d_val); |
4564 | 0 | } |
4565 | 0 | } |
4566 | | // Updated dynseg (.dynamic, in PT_DYNAMIC (PT_LOAD{PF_W})) has not been written. |
4567 | | // dynseg is in file_image[] but not in low_mem[]. |
4568 | | |
4569 | | // Relocate dynsym (DT_SYMTAB) which is below xct_va |
4570 | 0 | upx_uint64_t const off_dynsym = get_te64(&sec_dynsym->sh_offset); |
4571 | 0 | upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size); |
4572 | 0 | if ((upx_uint64_t)file_size < sz_dynsym |
4573 | 0 | || (upx_uint64_t)file_size < off_dynsym |
4574 | 0 | || ((upx_uint64_t)file_size - off_dynsym) < sz_dynsym) { |
4575 | 0 | throwCantPack("bad DT_SYMTAB"); |
4576 | 0 | } |
4577 | 0 | Elf64_Sym *dyntym = (Elf64_Sym *)lowmem.subref( |
4578 | 0 | "bad dynsym", off_dynsym, sz_dynsym); |
4579 | 0 | Elf64_Sym *sym = dyntym; |
4580 | 0 | for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) { |
4581 | 0 | upx_uint64_t symval = get_te64(&sym->st_value); |
4582 | 0 | unsigned symsec = get_te16(&sym->st_shndx); |
4583 | 0 | if (Elf64_Sym::SHN_UNDEF != symsec |
4584 | 0 | && Elf64_Sym::SHN_ABS != symsec |
4585 | 0 | && xct_off <= symval) { |
4586 | 0 | set_te64(&sym->st_value, asl_delta + symval); |
4587 | 0 | } |
4588 | 0 | if (Elf64_Sym::SHN_ABS == symsec && xct_off <= symval) { |
4589 | 0 | adjABS(sym, asl_delta); |
4590 | 0 | } |
4591 | 0 | } |
4592 | | |
4593 | | // Relocate Phdr virtual addresses, but not physical offsets and sizes |
4594 | 0 | unsigned char buf_notes[512]; memset(buf_notes, 0, sizeof(buf_notes)); |
4595 | 0 | unsigned len_notes = 0; |
4596 | 0 | Elf64_Phdr *phdr = (Elf64_Phdr *)lowmem.subref( |
4597 | 0 | "bad e_phoff", e_phoff, e_phnum * sizeof(Elf64_Phdr)); |
4598 | 0 | for (unsigned j = 0; j < e_phnum; ++j, ++phdr) { |
4599 | 0 | upx_uint64_t offset = get_te64(&phdr->p_offset); |
4600 | 0 | if (xct_off <= offset) { // above the extra page |
4601 | 0 | { |
4602 | | //set_te64(&phdr->p_offset, asl_delta + offset); // physical |
4603 | 0 | upx_uint64_t addr = get_te64(&phdr->p_paddr); |
4604 | 0 | set_te64(&phdr->p_paddr, asl_delta + addr); |
4605 | 0 | addr = get_te64(&phdr->p_vaddr); |
4606 | 0 | set_te64(&phdr->p_vaddr, asl_delta + addr); |
4607 | 0 | } |
4608 | 0 | } |
4609 | | // .p_filesz,.p_memsz are updated in ::pack3 |
4610 | 0 | } |
4611 | |
|
4612 | 0 | Elf64_Ehdr *const ehdr = (Elf64_Ehdr *)&lowmem[0]; |
4613 | 0 | upx_uint64_t e_entry = get_te64(&ehdr->e_entry); |
4614 | 0 | if (xct_off < e_entry) { |
4615 | 0 | set_te64(&ehdr->e_entry, asl_delta + e_entry); |
4616 | 0 | } |
4617 | | // Relocate Shdr; and Rela, Rel (below xct_off) |
4618 | 0 | unsigned const pal_xct_top = up8(pre_xct_top); |
4619 | 0 | set_te64(&ehdr->e_shoff, up8(pal_xct_top)); // Shdr alignment |
4620 | 0 | memcpy(&lowmem[pal_xct_top], shdri, e_shnum * sizeof(Elf64_Shdr)); |
4621 | 0 | shdro = (Elf64_Shdr *)&lowmem[pal_xct_top]; |
4622 | 0 | Elf64_Shdr *shdr = shdro; |
4623 | 0 | upx_uint64_t sz_shstrtab = get_te64(&sec_strndx->sh_size); |
4624 | 0 | for (unsigned j = 0; j < e_shnum; ++j, ++shdr) { |
4625 | 0 | unsigned sh_type = get_te32(&shdr->sh_type); |
4626 | 0 | upx_uint64_t sh_size = get_te64(&shdr->sh_size); |
4627 | 0 | upx_uint64_t sh_offset = get_te64(&shdr->sh_offset); |
4628 | 0 | upx_uint64_t sh_entsize = get_te64(&shdr->sh_entsize); |
4629 | 0 | if ((upx_uint64_t)file_size < sh_size |
4630 | 0 | || (upx_uint64_t)file_size < sh_offset |
4631 | 0 | || (Elf64_Shdr::SHT_NOBITS != sh_type |
4632 | 0 | && ((upx_uint64_t)file_size - sh_offset) < sh_size) ) { |
4633 | 0 | throwCantPack("bad SHT_STRNDX"); |
4634 | 0 | } |
4635 | | |
4636 | 0 | if (xct_off <= sh_offset) { |
4637 | 0 | upx_uint64_t addr = get_te64(&shdr->sh_addr); |
4638 | 0 | set_te64(&shdr->sh_addr, asl_delta + addr); |
4639 | 0 | set_te64(&shdr->sh_offset, asl_delta + sh_offset); |
4640 | 0 | } |
4641 | 0 | switch (sh_type) { |
4642 | 0 | default: break; |
4643 | 0 | case Elf64_Shdr::SHT_RELA: { |
4644 | 0 | if (sizeof(Elf64_Rela) != sh_entsize) { |
4645 | 0 | char msg[50]; |
4646 | 0 | snprintf(msg, sizeof(msg), "bad Rela.sh_entsize %lu", (long)sh_entsize); |
4647 | 0 | throwCantPack(msg); |
4648 | 0 | } |
4649 | 0 | plt_va = ~0ull; |
4650 | 0 | Elf64_Rela *const relb = (Elf64_Rela *)lowmem.subref( |
4651 | 0 | "bad Rela offset", sh_offset, sh_size); |
4652 | 0 | Elf64_Rela *rela = relb; |
4653 | 0 | for (int k = sh_size / sh_entsize; --k >= 0; ++rela) { |
4654 | 0 | upx_uint64_t r_addend = get_te64(&rela->r_addend); |
4655 | 0 | upx_uint64_t r_offset = get_te64(&rela->r_offset); |
4656 | 0 | upx_uint64_t r_info = get_te64(&rela->r_info); |
4657 | 0 | unsigned r_type = ELF64_R_TYPE(r_info); |
4658 | 0 | if (xct_off <= r_offset) { |
4659 | 0 | set_te64(&rela->r_offset, asl_delta + r_offset); |
4660 | 0 | } |
4661 | 0 | if (Elf64_Ehdr::EM_AARCH64 == e_machine) switch (r_type) { |
4662 | 0 | default: { |
4663 | 0 | char msg[90]; snprintf(msg, sizeof(msg), |
4664 | 0 | "unexpected relocation %#x [%#x]", |
4665 | 0 | r_type, -1 + (unsigned)(sh_size / sh_entsize) - k); |
4666 | 0 | throwCantPack(msg); |
4667 | 0 | } break; |
4668 | 0 | case R_AARCH64_ABS64: // FALL THROUGH |
4669 | 0 | case R_AARCH64_GLOB_DAT: // FALL THROUGH |
4670 | 0 | case R_AARCH64_RELATIVE: { |
4671 | 0 | if (xct_off <= r_addend) { |
4672 | 0 | set_te64(&rela->r_addend, asl_delta + r_addend); |
4673 | 0 | } |
4674 | 0 | } break; |
4675 | 0 | case R_AARCH64_JUMP_SLOT: { |
4676 | | // .rela.plt contains offset of the "first time" target |
4677 | 0 | if (plt_va > r_offset) { |
4678 | 0 | plt_va = r_offset; |
4679 | 0 | } |
4680 | 0 | upx_uint64_t d = elf_get_offset_from_address(r_offset); |
4681 | 0 | upx_uint64_t w = get_te64(&file_image[d]); |
4682 | 0 | if (xct_off <= w) { |
4683 | 0 | set_te64(&file_image[d], asl_delta + w); |
4684 | 0 | } |
4685 | 0 | ++n_jmp_slot; |
4686 | 0 | } break; |
4687 | 0 | } |
4688 | 0 | } |
4689 | 0 | }; break; |
4690 | 0 | case Elf64_Shdr::SHT_REL: { |
4691 | 0 | if (sizeof(Elf64_Rel) != sh_entsize) { |
4692 | 0 | char msg[50]; |
4693 | 0 | snprintf(msg, sizeof(msg), "bad Rel.sh_entsize %lu", (long)sh_entsize); |
4694 | 0 | throwCantPack(msg); |
4695 | 0 | } |
4696 | 0 | Elf64_Rel *rel = (Elf64_Rel *)lowmem.subref( |
4697 | 0 | "bad Rel sh_offset", sh_offset, sh_size); |
4698 | 0 | for (int k = sh_size / sh_entsize; --k >= 0; ++rel) { |
4699 | 0 | upx_uint64_t r_offset = get_te64(&rel->r_offset); |
4700 | 0 | if (xct_off <= r_offset) { |
4701 | 0 | set_te64(&rel->r_offset, asl_delta + r_offset); |
4702 | 0 | } |
4703 | | // r_offset must be in 2nd PT_LOAD; .p_vaddr was already relocated |
4704 | 0 | upx_uint64_t d = elf_get_offset_from_address(asl_delta + r_offset); |
4705 | 0 | upx_uint64_t w = get_te64(&file_image[d]); |
4706 | 0 | upx_uint64_t r_info = get_te64(&rel->r_info); |
4707 | 0 | unsigned r_type = ELF64_R_TYPE(r_info); |
4708 | 0 | if (xct_off <= w |
4709 | 0 | && Elf64_Ehdr::EM_AARCH64 == e_machine |
4710 | 0 | && ( R_AARCH64_RELATIVE == r_type |
4711 | 0 | || R_AARCH64_JUMP_SLOT == r_type)) { |
4712 | 0 | set_te64(&file_image[d], asl_delta + w); |
4713 | 0 | } |
4714 | 0 | } |
4715 | 0 | }; break; |
4716 | 0 | case Elf64_Shdr::SHT_NOTE: { |
4717 | 0 | if (!(Elf64_Shdr::SHF_ALLOC & get_te64(&shdr->sh_flags))) { |
4718 | | // example: version number of 'gold' linker (static binder) |
4719 | 0 | if (sizeof(buf_notes) < (sh_size + len_notes)) { |
4720 | 0 | throwCantPack("SHT_NOTEs too big"); |
4721 | 0 | } |
4722 | 0 | set_te64(&shdro[j].sh_offset, |
4723 | 0 | len_notes + (e_shnum * sizeof(Elf64_Shdr)) + xct_off); |
4724 | 0 | memcpy(&buf_notes[len_notes], &file_image[sh_offset], sh_size); |
4725 | 0 | len_notes += sh_size; |
4726 | 0 | } |
4727 | 0 | else { // SHF_ALLOC: in PT_LOAD; but move sh_addr and sh_offset |
4728 | | // Not sure why we need this conditional. |
4729 | | // Anyway, some Android have multiple SHT_NOTE sections. |
4730 | 0 | if (xct_off <= sh_offset) { |
4731 | 0 | upx_uint64_t pos = xct_off + e_shnum * sizeof(Elf64_Shdr); |
4732 | 0 | set_te64(&shdr->sh_addr, pos); |
4733 | 0 | set_te64(&shdr->sh_offset, pos); |
4734 | 0 | } |
4735 | 0 | } |
4736 | 0 | }; break; |
4737 | 0 | } // end switch (sh_type) |
4738 | 0 | } |
4739 | | // shstrndx will move |
4740 | 0 | set_te64(&shdro[get_te16(&ehdri.e_shstrndx)].sh_offset, |
4741 | 0 | len_notes + e_shnum * sizeof(Elf64_Shdr) + pal_xct_top); |
4742 | | |
4743 | | // ("Re-")write all changes below pal_xct_top |
4744 | 0 | fo->seek(0, SEEK_SET); |
4745 | 0 | fo->write(lowmem, pal_xct_top); |
4746 | 0 | total_in = pal_xct_top; |
4747 | | |
4748 | | // New copy of Shdr |
4749 | 0 | Elf64_Shdr blank; memset(&blank, 0, sizeof(blank)); |
4750 | 0 | set_te64(&blank.sh_offset, xct_off); // hint for "upx -d" |
4751 | 0 | fpad8(fo, total_out); // Shdr alignment |
4752 | 0 | fo->write(&blank, sizeof(blank)); |
4753 | 0 | fo->write(&shdro[1], (-1+ e_shnum) * sizeof(Elf64_Shdr)); |
4754 | |
|
4755 | 0 | if (len_notes) { |
4756 | 0 | fo->write(buf_notes, len_notes); |
4757 | 0 | } |
4758 | | |
4759 | | // New copy of Shdr[.e_shstrndx].[ sh_offset, +.sh_size ) |
4760 | 0 | fo->write(shstrtab, sz_shstrtab); |
4761 | |
|
4762 | 0 | sz_elf_hdrs = fpad8(fo, total_out); |
4763 | 0 | total_out = sz_elf_hdrs; |
4764 | | //xct_off += asl_delta; // wait until ::pack3 |
4765 | 0 | unsigned d = asl_delta + pal_xct_top - sz_elf_hdrs; |
4766 | 0 | fo->seek(d, SEEK_CUR); |
4767 | 0 | total_out += d; |
4768 | 0 | } |
4769 | | |
4770 | | // asl (ANdroid Shared Library) creates a big mess! |
4771 | | void PackLinuxElf32::asl_pack2_Shdrs(OutputFile *fo, unsigned pre_xct_top) |
4772 | 0 | { |
4773 | 0 | if (!fo) { |
4774 | 0 | return; |
4775 | 0 | } |
4776 | | // In order to pacify the runtime linker on Android "O" ("Oreo"), |
4777 | | // we will splice-in a 4KiB page that contains an "extra" copy |
4778 | | // of the Shdr, any PT_NOTE above xct_off, and shstrtab. |
4779 | | // File order: Ehdr, Phdr[], section contents below xct_off, |
4780 | | // Shdr_copy[], PT_NOTEs.hi, shstrtab. |
4781 | 0 | if (is_asl) |
4782 | 0 | xct_va += asl_delta; |
4783 | | //xct_off += asl_delta; // not until ::pack3() |
4784 | |
|
4785 | 0 | total_in = pre_xct_top; |
4786 | | |
4787 | | // Relocate PT_DYNAMIC (in PT_LOAD with PF_W) |
4788 | 0 | Elf32_Dyn *dyn = const_cast<Elf32_Dyn *>(dynseg); |
4789 | 0 | for (; dyn->d_tag; ++dyn) { |
4790 | 0 | upx_uint32_t d_tag = get_te32(&dyn->d_tag); |
4791 | 0 | if (Elf32_Dyn::DT_FINI == d_tag |
4792 | 0 | || Elf32_Dyn::DT_FINI_ARRAY == d_tag |
4793 | 0 | || Elf32_Dyn::DT_INIT_ARRAY == d_tag |
4794 | 0 | || Elf32_Dyn::DT_PREINIT_ARRAY == d_tag |
4795 | 0 | || Elf32_Dyn::DT_PLTGOT == d_tag) { |
4796 | 0 | upx_uint32_t d_val = get_te32(&dyn->d_val); |
4797 | 0 | set_te32(&dyn->d_val, asl_delta + d_val); |
4798 | 0 | } |
4799 | 0 | } |
4800 | | // Updated dynseg (.dynamic, in PT_DYNAMIC (PT_LOAD{PF_W})) has not been written. |
4801 | | // dynseg is in file_image[] but not in low_mem[]. |
4802 | | |
4803 | | // Relocate dynsym (DT_SYMTAB) which is below xct_va |
4804 | 0 | upx_uint32_t const off_dynsym = get_te32(&sec_dynsym->sh_offset); |
4805 | 0 | upx_uint32_t const sz_dynsym = get_te32(&sec_dynsym->sh_size); |
4806 | 0 | if ((upx_uint32_t)file_size < sz_dynsym |
4807 | 0 | || (upx_uint32_t)file_size < off_dynsym |
4808 | 0 | || ((upx_uint32_t)file_size - off_dynsym) < sz_dynsym) { |
4809 | 0 | throwCantPack("bad DT_SYMTAB"); |
4810 | 0 | } |
4811 | 0 | Elf32_Sym *dyntym = (Elf32_Sym *)lowmem.subref( |
4812 | 0 | "bad dynsym", off_dynsym, sz_dynsym); |
4813 | 0 | Elf32_Sym *sym = dyntym; |
4814 | 0 | for (int j = sz_dynsym / sizeof(Elf32_Sym); --j>=0; ++sym) { |
4815 | 0 | upx_uint32_t symval = get_te32(&sym->st_value); |
4816 | 0 | unsigned symsec = get_te16(&sym->st_shndx); |
4817 | 0 | if (Elf32_Sym::SHN_UNDEF != symsec |
4818 | 0 | && Elf32_Sym::SHN_ABS != symsec |
4819 | 0 | && xct_off <= symval) { |
4820 | 0 | set_te32(&sym->st_value, asl_delta + symval); |
4821 | 0 | } |
4822 | 0 | if (Elf32_Sym::SHN_ABS == symsec && xct_off <= symval) { |
4823 | 0 | adjABS(sym, asl_delta); |
4824 | 0 | } |
4825 | 0 | } |
4826 | | |
4827 | | // Relocate Phdr virtual addresses, but not physical offsets and sizes |
4828 | 0 | unsigned char buf_notes[512]; memset(buf_notes, 0, sizeof(buf_notes)); |
4829 | 0 | unsigned len_notes = 0; |
4830 | 0 | Elf32_Phdr *phdr = (Elf32_Phdr *)lowmem.subref( |
4831 | 0 | "bad e_phoff", e_phoff, e_phnum * sizeof(Elf32_Phdr)); |
4832 | 0 | for (unsigned j = 0; j < e_phnum; ++j, ++phdr) { |
4833 | 0 | upx_uint32_t offset = get_te32(&phdr->p_offset); |
4834 | 0 | if (xct_off <= offset) { // above the extra page |
4835 | 0 | { |
4836 | | //set_te32(&phdr->p_offset, asl_delta + offset); // physical |
4837 | 0 | upx_uint32_t v_addr = get_te32(&phdr->p_vaddr); |
4838 | 0 | set_te32(&phdr->p_vaddr, asl_delta + v_addr); |
4839 | 0 | upx_uint32_t p_addr = get_te32(&phdr->p_paddr); |
4840 | 0 | set_te32(&phdr->p_paddr, asl_delta + p_addr); |
4841 | 0 | } |
4842 | 0 | } |
4843 | | // .p_filesz,.p_memsz are updated in ::pack3 |
4844 | 0 | } |
4845 | |
|
4846 | 0 | Elf32_Ehdr *const ehdr = (Elf32_Ehdr *)&lowmem[0]; |
4847 | 0 | upx_uint32_t e_entry = get_te32(&ehdr->e_entry); |
4848 | 0 | if (xct_off <= e_entry) { // FIXME: --android-shlib is different |
4849 | 0 | set_te32(&ehdr->e_entry, asl_delta + e_entry); |
4850 | 0 | } |
4851 | | // Relocate Shdr; and Rela, Rel (below xct_off) |
4852 | 0 | unsigned const pal_xct_top = up4(pre_xct_top); |
4853 | 0 | set_te32(&ehdr->e_shoff, pal_xct_top); // Shdr alignment |
4854 | 0 | memcpy(&lowmem[pal_xct_top], shdri, e_shnum * sizeof(Elf32_Shdr)); |
4855 | 0 | shdro = (Elf32_Shdr *)&lowmem[pal_xct_top]; |
4856 | 0 | Elf32_Shdr *shdr = shdro; |
4857 | 0 | upx_uint32_t sz_shstrtab = get_te32(&sec_strndx->sh_size); |
4858 | 0 | for (unsigned j = 0; j < e_shnum; ++j, ++shdr) { |
4859 | 0 | unsigned sh_type = get_te32(&shdr->sh_type); |
4860 | 0 | unsigned sh_flags = get_te32(&shdr->sh_flags); |
4861 | 0 | upx_uint32_t sh_size = get_te32(&shdr->sh_size); |
4862 | 0 | upx_uint32_t sh_offset = get_te32(&shdr->sh_offset); |
4863 | 0 | upx_uint32_t sh_entsize = get_te32(&shdr->sh_entsize); |
4864 | 0 | if ((upx_uint32_t)file_size < sh_size |
4865 | 0 | || (upx_uint32_t)file_size < sh_offset |
4866 | 0 | || (Elf32_Shdr::SHT_NOBITS != sh_type |
4867 | 0 | && ((upx_uint32_t)file_size - sh_offset) < sh_size) ) { |
4868 | 0 | throwCantPack("bad SHT_STRNDX"); |
4869 | 0 | } |
4870 | | |
4871 | 0 | if (xct_off <= sh_offset && Elf32_Shdr::SHF_ALLOC & sh_flags) { |
4872 | 0 | upx_uint32_t addr = get_te32(&shdr->sh_addr); |
4873 | 0 | set_te32(&shdr->sh_addr, asl_delta + addr); |
4874 | 0 | set_te32(&shdr->sh_offset, asl_delta + sh_offset); |
4875 | 0 | } |
4876 | 0 | switch (sh_type) { |
4877 | 0 | default: break; |
4878 | 0 | case Elf32_Shdr::SHT_RELA: { // 32-bit Elf_Rela is unused (by convention) |
4879 | 0 | if (sizeof(Elf32_Rela) != sh_entsize) { |
4880 | 0 | char msg[50]; |
4881 | 0 | snprintf(msg, sizeof(msg), "bad Rela.sh_entsize %lu", (long)sh_entsize); |
4882 | 0 | throwCantPack(msg); |
4883 | 0 | } |
4884 | 0 | plt_va = ~0ull; |
4885 | 0 | Elf32_Rela *const relb = (Elf32_Rela *)lowmem.subref( |
4886 | 0 | "bad Rela offset", sh_offset, sh_size); |
4887 | 0 | Elf32_Rela *rela = relb; |
4888 | 0 | for (int k = sh_size / sh_entsize; --k >= 0; ++rela) { |
4889 | 0 | upx_uint32_t r_addend = get_te32(&rela->r_addend); |
4890 | 0 | upx_uint32_t r_offset = get_te32(&rela->r_offset); |
4891 | 0 | upx_uint32_t r_info = get_te32(&rela->r_info); |
4892 | 0 | unsigned r_type = ELF32_R_TYPE(r_info); |
4893 | 0 | if (xct_off <= r_offset) { |
4894 | 0 | set_te32(&rela->r_offset, asl_delta + r_offset); |
4895 | 0 | } |
4896 | 0 | if (Elf32_Ehdr::EM_386 == e_machine) switch (r_type) { |
4897 | 0 | default: { |
4898 | 0 | char msg[90]; snprintf(msg, sizeof(msg), |
4899 | 0 | "unexpected relocation %#x [%#x]", |
4900 | 0 | r_type, -1 + (unsigned)(sh_size / sh_entsize) - k); |
4901 | 0 | throwCantPack(msg); |
4902 | 0 | } break; |
4903 | 0 | case R_386_32: // FALL THROUGH |
4904 | 0 | case R_386_GLOB_DAT: // FALL THROUGH |
4905 | 0 | case R_386_RELATIVE: { |
4906 | 0 | if (xct_off <= r_addend) { |
4907 | 0 | set_te32(&rela->r_addend, asl_delta + r_addend); |
4908 | 0 | } |
4909 | 0 | } break; |
4910 | 0 | case R_386_JMP_SLOT: { |
4911 | | // .rela.plt contains offset of the "first time" target |
4912 | 0 | if (plt_va > r_offset) { |
4913 | 0 | plt_va = r_offset; |
4914 | 0 | } |
4915 | 0 | upx_uint32_t d = elf_get_offset_from_address(r_offset); |
4916 | 0 | upx_uint32_t w = get_te32(&file_image[d]); |
4917 | 0 | if (xct_off <= w) { |
4918 | 0 | set_te32(&file_image[d], asl_delta + w); |
4919 | 0 | } |
4920 | 0 | ++n_jmp_slot; |
4921 | 0 | } break; |
4922 | 0 | } // end EM_386 r_type |
4923 | 0 | else if (Elf32_Ehdr::EM_ARM == e_machine) switch (r_type) { |
4924 | 0 | default: { |
4925 | 0 | char msg[90]; snprintf(msg, sizeof(msg), |
4926 | 0 | "unexpected relocation %#x [%#x]", |
4927 | 0 | r_type, -1 + (unsigned)(sh_size / sh_entsize) - k); |
4928 | 0 | throwCantPack(msg); |
4929 | 0 | } break; |
4930 | 0 | case R_ARM_ABS32: // FALL THROUGH |
4931 | 0 | case R_ARM_GLOB_DAT: // FALL THROUGH |
4932 | 0 | case R_ARM_RELATIVE: { |
4933 | 0 | if (xct_off <= r_addend) { |
4934 | 0 | set_te32(&rela->r_addend, asl_delta + r_addend); |
4935 | 0 | } |
4936 | 0 | } break; |
4937 | 0 | case R_ARM_JUMP_SLOT: { |
4938 | | // .rela.plt contains offset of the "first time" target |
4939 | 0 | if (plt_va > r_offset) { |
4940 | 0 | plt_va = r_offset; |
4941 | 0 | } |
4942 | 0 | upx_uint32_t d = elf_get_offset_from_address(r_offset); |
4943 | 0 | upx_uint32_t w = get_te32(&file_image[d]); |
4944 | 0 | if (xct_off <= w) { |
4945 | 0 | set_te32(&file_image[d], asl_delta + w); |
4946 | 0 | } |
4947 | 0 | ++n_jmp_slot; |
4948 | 0 | } break; |
4949 | 0 | } // end EM_ARM r_type |
4950 | 0 | else { |
4951 | 0 | char msg[40]; snprintf(msg, sizeof(msg), |
4952 | 0 | "Unknown architecture %d", this->e_machine); |
4953 | 0 | throwCantPack(msg); |
4954 | 0 | } // end e_machine |
4955 | 0 | } |
4956 | 0 | }; break; // end Elf32_Shdr::SHT_RELA |
4957 | 0 | case Elf32_Shdr::SHT_REL: { |
4958 | 0 | if (sizeof(Elf32_Rel) != sh_entsize) { |
4959 | 0 | char msg[50]; |
4960 | 0 | snprintf(msg, sizeof(msg), "bad Rel.sh_entsize %lu", (long)sh_entsize); |
4961 | 0 | throwCantPack(msg); |
4962 | 0 | } |
4963 | 0 | Elf32_Rel *rel = (Elf32_Rel *)lowmem.subref( |
4964 | 0 | "bad Rel sh_offset", sh_offset, sh_size); |
4965 | 0 | for (int k = sh_size / sh_entsize; --k >= 0; ++rel) { |
4966 | 0 | upx_uint32_t r_offset = get_te32(&rel->r_offset); |
4967 | 0 | if (xct_off <= r_offset) { |
4968 | 0 | set_te32(&rel->r_offset, asl_delta + r_offset); |
4969 | 0 | } |
4970 | | // r_offset must be in 2nd PT_LOAD; .p_vaddr was already relocated |
4971 | 0 | upx_uint32_t d = elf_get_offset_from_address(r_offset); |
4972 | 0 | upx_uint32_t w = get_te32(&file_image[d]); |
4973 | 0 | upx_uint32_t r_info = get_te32(&rel->r_info); |
4974 | 0 | unsigned r_type = ELF32_R_TYPE(r_info); |
4975 | | //printf("d=%#x w=%#x r_info=%#x\n", d, w, r_info); |
4976 | | // FIXME: why change file_image[d] instead of lowmem[d] ? |
4977 | 0 | if (Elf32_Ehdr::EM_386 == e_machine) switch (r_type) { |
4978 | 0 | default: { |
4979 | 0 | char msg[90]; snprintf(msg, sizeof(msg), |
4980 | 0 | "unexpected relocation %#x [%#x]", |
4981 | 0 | r_type, -1 + (unsigned)(sh_size / sh_entsize) - k); |
4982 | 0 | throwCantPack(msg); |
4983 | 0 | } break; |
4984 | 0 | case R_386_32: // FALL THROUGH |
4985 | 0 | case R_386_GLOB_DAT: // FALL THROUGH |
4986 | 0 | case R_386_RELATIVE: { |
4987 | 0 | if (xct_off <= w) { |
4988 | 0 | set_te32(&file_image[d], asl_delta + w); |
4989 | 0 | } |
4990 | 0 | } break; |
4991 | 0 | case R_386_JMP_SLOT: { |
4992 | | // .rela.plt contains offset of the "first time" target |
4993 | 0 | if (plt_va > r_offset) { |
4994 | 0 | plt_va = r_offset; |
4995 | 0 | } |
4996 | 0 | if (xct_off <= w) { |
4997 | 0 | set_te32(&file_image[d], asl_delta + w); |
4998 | 0 | } |
4999 | 0 | ++n_jmp_slot; |
5000 | 0 | } break; |
5001 | 0 | } // end EM_386 r_type |
5002 | 0 | else if (Elf32_Ehdr::EM_ARM == e_machine) switch (r_type) { |
5003 | 0 | default: { |
5004 | 0 | char msg[90]; snprintf(msg, sizeof(msg), |
5005 | 0 | "unexpected relocation %#x [%#x]", |
5006 | 0 | r_type, -1 + (unsigned)(sh_size / sh_entsize) - k); |
5007 | 0 | throwCantPack(msg); |
5008 | 0 | } break; |
5009 | 0 | case R_ARM_ABS32: // FALL THROUGH |
5010 | 0 | case R_ARM_GLOB_DAT: // FALL THROUGH |
5011 | 0 | case R_ARM_RELATIVE: { |
5012 | 0 | if (xct_off <= w) { |
5013 | 0 | set_te32(&file_image[d], asl_delta + w); |
5014 | 0 | } |
5015 | 0 | } break; |
5016 | 0 | case R_ARM_JUMP_SLOT: { |
5017 | | // .rela.plt contains offset of the "first time" target |
5018 | 0 | if (plt_va > r_offset) { |
5019 | 0 | plt_va = r_offset; |
5020 | 0 | } |
5021 | 0 | if (xct_off <= w) { |
5022 | 0 | set_te32(&file_image[d], asl_delta + w); |
5023 | 0 | } |
5024 | 0 | ++n_jmp_slot; |
5025 | 0 | } break; |
5026 | 0 | } // end EM_ARM r_type |
5027 | 0 | else { |
5028 | 0 | char msg[40]; snprintf(msg, sizeof(msg), |
5029 | 0 | "Unknown architecture %d", this->e_machine); |
5030 | 0 | throwCantPack(msg); |
5031 | 0 | } // end e_machine |
5032 | 0 | } // end rel |
5033 | 0 | }; break; // end Elf32_Shdr::SHT_REL |
5034 | 0 | case Elf32_Shdr::SHT_NOTE: { |
5035 | 0 | if (!(Elf32_Shdr::SHF_ALLOC & sh_flags)) { |
5036 | | // example: version number of 'gold' linker (static binder) |
5037 | 0 | if (sizeof(buf_notes) < (sh_size + len_notes)) { |
5038 | 0 | throwCantPack("SHT_NOTEs too big"); |
5039 | 0 | } |
5040 | 0 | set_te32(&shdro[j].sh_offset, |
5041 | 0 | len_notes + (e_shnum * sizeof(Elf32_Shdr)) + xct_off); |
5042 | 0 | memcpy(&buf_notes[len_notes], &file_image[sh_offset], sh_size); |
5043 | 0 | len_notes += sh_size; |
5044 | 0 | } |
5045 | 0 | else { // SHF_ALLOC: in PT_LOAD; but move sh_addr and sh_offset |
5046 | | // Not sure why we need this conditional. |
5047 | | // Anyway, some Android have multiple SHT_NOTE sections. |
5048 | 0 | if (xct_off <= sh_offset) { |
5049 | 0 | upx_uint32_t pos = xct_off + e_shnum * sizeof(Elf32_Shdr); |
5050 | | //set_te32(&shdr->sh_addr, pos); |
5051 | 0 | set_te32(&shdr->sh_offset, pos); |
5052 | 0 | } |
5053 | 0 | } |
5054 | 0 | }; break; // end Elf32_Shdr::SHT_NOTE |
5055 | 0 | case Elf32_Shdr::SHT_ARM_ATTRIBUTES: { |
5056 | 0 | sec_arm_attr = shdr; |
5057 | 0 | }; break; |
5058 | 0 | } // end switch (sh_type) |
5059 | 0 | } |
5060 | | // shstrndx will move |
5061 | 0 | set_te32(&shdro[get_te16(&ehdri.e_shstrndx)].sh_offset, |
5062 | 0 | len_notes + e_shnum * sizeof(Elf32_Shdr) + up8(pal_xct_top)); |
5063 | | |
5064 | | // Write all changes below pal_xct_top |
5065 | | // FIXME: why is this any more than Ehdr + Phdrs? |
5066 | 0 | if (fo) { |
5067 | 0 | fo->seek(0, SEEK_SET); |
5068 | 0 | fo->write(lowmem, pal_xct_top); |
5069 | 0 | } |
5070 | 0 | total_out = pal_xct_top; |
5071 | 0 | total_in = pal_xct_top; |
5072 | | |
5073 | | // New copy of Shdr |
5074 | 0 | Elf32_Shdr blank; memset(&blank, 0, sizeof(blank)); |
5075 | 0 | set_te32(&blank.sh_offset, xct_off); // hint for "upx -d" |
5076 | 0 | set_te32(&shdro->sh_offset, xct_off); // hint for "upx -d" |
5077 | 0 | total_out = fpad8(fo, total_out); // Shdr alignment |
5078 | 0 | unsigned arm_attr_off = 0; |
5079 | 0 | if (sec_arm_attr) { |
5080 | 0 | arm_attr_off = get_te32(&sec_arm_attr->sh_offset); |
5081 | 0 | set_te32(&sec_arm_attr->sh_offset, |
5082 | 0 | total_out + e_shnum*sizeof(Elf32_Shdr) |
5083 | 0 | + len_notes + sz_shstrtab); |
5084 | 0 | } |
5085 | 0 | if (fo) { |
5086 | 0 | fo->write(&blank, sizeof(blank)); |
5087 | 0 | fo->write(&shdro[1], (-1+ e_shnum) * sizeof(Elf32_Shdr)); |
5088 | 0 | if (len_notes) { |
5089 | 0 | fo->write(buf_notes, len_notes); |
5090 | 0 | } |
5091 | | // New copy of Shdr[.e_shstrndx].[ sh_offset, +.sh_size ) |
5092 | 0 | fo->write(shstrtab, sz_shstrtab); |
5093 | |
|
5094 | 0 | if (sec_arm_attr) { |
5095 | 0 | fo->write(&file_image[arm_attr_off], |
5096 | 0 | get_te32(&sec_arm_attr->sh_size)); |
5097 | 0 | } |
5098 | 0 | } |
5099 | |
|
5100 | 0 | sz_elf_hdrs = fpad8(fo, total_out); |
5101 | 0 | total_out = sz_elf_hdrs; |
5102 | | //xct_off += asl_delta; // wait until ::pack3 |
5103 | 0 | total_out = fpadN(fo, asl_delta - (sz_elf_hdrs - pal_xct_top)); |
5104 | 0 | } |
5105 | | |
5106 | | void PackLinuxElf64::pack1(OutputFile * /*fo*/, Filter &ft) |
5107 | 0 | { |
5108 | 0 | fi->seek(0, SEEK_SET); |
5109 | 0 | fi->readx(&ehdri, sizeof(ehdri)); |
5110 | 0 | assert(e_phoff == sizeof(Elf64_Ehdr)); // checked by canPack() |
5111 | 0 | sz_phdrs = e_phnum * get_te16(&ehdri.e_phentsize); |
5112 | | |
5113 | | // We compress separate pieces (usually each PT_LOAD, plus the gaps in the file |
5114 | | // that are not covered by any PT_LOAD), but currently at run time there can be |
5115 | | // only one decompressor method. |
5116 | | // Therefore we must plan ahead because Packer::compressWithFilters tries |
5117 | | // to find the smallest result among the available methods, for one piece only. |
5118 | | // In the future we may allow more than one decompression method at run time. |
5119 | | // For now we must choose only one, and force PackUnix::packExtent |
5120 | | // (==> compressWithFilters) to use it. |
5121 | 0 | int nfilters = 0; |
5122 | 0 | { |
5123 | 0 | int const *fp = getFilters(); |
5124 | 0 | while (FT_END != *fp++) { |
5125 | 0 | ++nfilters; |
5126 | 0 | } |
5127 | 0 | } |
5128 | 0 | { |
5129 | 0 | int npieces = 1; // tail after highest PT_LOAD |
5130 | 0 | Elf64_Phdr *phdr = phdri; |
5131 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
5132 | 0 | if (is_LOAD(phdr)) { |
5133 | 0 | unsigned const flags = get_te32(&phdr->p_flags); |
5134 | 0 | unsigned offset = get_te64(&phdr->p_offset); |
5135 | 0 | if (!xct_off // not shlib |
5136 | | // new-style shlib: PT_LOAD[0] has symbol table |
5137 | | // which must not be compressed, but also lacks PF_X |
5138 | 0 | || (Elf64_Phdr::PF_X & flags) |
5139 | | // Read-only, non-first PT_LOAD is _assumed_ to be compressible |
5140 | 0 | || (!(Elf64_Phdr::PF_W & flags) && 0!=offset)) |
5141 | 0 | { |
5142 | 0 | ++npieces; // will attempt compression of this PT_LOAD |
5143 | 0 | } |
5144 | 0 | } |
5145 | 0 | } |
5146 | 0 | uip->ui_total_passes += npieces; |
5147 | 0 | } |
5148 | 0 | int methods[256]; |
5149 | 0 | unsigned nmethods = prepareMethods(methods, ph.method, getCompressionMethods(M_ALL, ph.level)); |
5150 | 0 | if (1 < nmethods) { // Many are available, but we must choose only one |
5151 | 0 | uip->ui_total_passes += 1; // the batch for output |
5152 | 0 | uip->ui_total_passes *= nmethods * (1+ nfilters); // finding smallest total |
5153 | 0 | PackHeader orig_ph = ph; |
5154 | 0 | Filter orig_ft = ft; |
5155 | 0 | unsigned max_offset = 0; |
5156 | 0 | unsigned sz_best= ~0u; |
5157 | 0 | int method_best = 0; |
5158 | 0 | for (unsigned k = 0; k < nmethods; ++k) { // FIXME: parallelize; cost: working space |
5159 | 0 | unsigned sz_this = 0; |
5160 | 0 | Elf64_Phdr *phdr = phdri; |
5161 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
5162 | 0 | if (is_LOAD(phdr)) { |
5163 | 0 | unsigned const flags = get_te32(&phdr->p_flags); |
5164 | 0 | unsigned offset = get_te64(&phdr->p_offset); |
5165 | 0 | unsigned filesz = get_te64(&phdr->p_filesz); |
5166 | 0 | max_offset = UPX_MAX(max_offset, filesz + offset); |
5167 | 0 | if (!xct_off // not shlib |
5168 | | // new-style shlib: PT_LOAD[0] has symbol table |
5169 | | // which must not be compressed, but also lacks PF_X |
5170 | 0 | || (Elf64_Phdr::PF_X & flags) |
5171 | | // Read-only, non-first PT_LOAD is _assumed_ to be compressible |
5172 | 0 | || (!(Elf64_Phdr::PF_W & flags) && 0!=offset)) |
5173 | 0 | { |
5174 | 0 | if (xct_off && 0==offset) { // old-style shlib |
5175 | 0 | offset = xct_off; |
5176 | 0 | filesz -= xct_off; |
5177 | 0 | } |
5178 | 0 | fi->seek(offset, SEEK_SET); |
5179 | 0 | fi->readx(ibuf, filesz); |
5180 | 0 | ft = orig_ft; |
5181 | 0 | ph = orig_ph; |
5182 | 0 | ph.set_method(ph_force_method(methods[k])); |
5183 | 0 | ph.u_len = filesz; |
5184 | 0 | compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true); |
5185 | 0 | sz_this += ph.c_len; |
5186 | 0 | } |
5187 | 0 | } |
5188 | 0 | } |
5189 | 0 | unsigned const sz_tail = file_size - max_offset; // debuginfo, etc. |
5190 | 0 | if (sz_tail) { |
5191 | 0 | fi->seek(max_offset, SEEK_SET); |
5192 | 0 | fi->readx(ibuf, sz_tail); |
5193 | 0 | ft = orig_ft; |
5194 | 0 | ph = orig_ph; |
5195 | 0 | ph.set_method(ph_force_method(methods[k])); |
5196 | 0 | ph.u_len = sz_tail; |
5197 | 0 | compressWithFilters(&ft, OVERHEAD, NULL_cconf, 10, true); |
5198 | 0 | sz_this += ph.c_len; |
5199 | 0 | } |
5200 | | // FIXME: loader size also depends on method |
5201 | 0 | if (sz_best > sz_this) { |
5202 | 0 | sz_best = sz_this; |
5203 | 0 | method_best = methods[k]; |
5204 | 0 | } |
5205 | 0 | } |
5206 | 0 | ft = orig_ft; |
5207 | 0 | ph = orig_ph; |
5208 | 0 | ph.set_method(ph_force_method(method_best)); |
5209 | 0 | } |
5210 | |
|
5211 | 0 | Elf64_Phdr *phdr = phdri; |
5212 | 0 | for (unsigned j=0; j < e_phnum; ++phdr, ++j) { |
5213 | 0 | unsigned const type = get_te32(&phdr->p_type); |
5214 | 0 | if (PT_GNU_STACK64 == type || PT_NOTE64 == type) { |
5215 | 0 | add_phdrx(phdr); // PT_GNU_STACK64, PT_NOTE64 |
5216 | 0 | } |
5217 | 0 | if (PT_LOAD == type) { |
5218 | 0 | unsigned x = get_te64(&phdr->p_align) >> lg2_page; |
5219 | 0 | while (x>>=1) { |
5220 | 0 | ++lg2_page; |
5221 | 0 | } |
5222 | 0 | } |
5223 | 0 | if (PT_GNU_RELRO64 == type |
5224 | 0 | && 16 < lg2_page) { |
5225 | | // x86* allows 4K, 2M, 1G |
5226 | | // arm32 and arm64 both allow 4K, 16K, 64K; Apple Silicon uses 16K |
5227 | | // Oracle 5.4.17-2136.314.6.2.el8uek.aarch64 demands 64K |
5228 | | // PowerPC and PowerPC64 has 4K, 64K, 1M (?), 16M (?) |
5229 | | // MIPS allows any power of 2 from 4K through 64K |
5230 | | |
5231 | | // If 64K < .p_align then we assume that 4K is also accepted. |
5232 | | // .p_align can be like 2M, which is a huge over-estimate. |
5233 | | // RELRO ends on a page boundary: usually close to actual page_size |
5234 | 0 | unsigned offset = get_te64(&phdr->p_offset); |
5235 | 0 | unsigned filesz = get_te64(&phdr->p_filesz); |
5236 | 0 | if (!(0xfff & (filesz + offset))) { // a 4KiB boundary |
5237 | 0 | unsigned b = 12; |
5238 | 0 | while (!(~(~0u << b) & (filesz + offset))) { |
5239 | 0 | ++b; |
5240 | 0 | } |
5241 | 0 | lg2_page = umin(lg2_page, -1+ b); |
5242 | 0 | } |
5243 | 0 | } |
5244 | 0 | } |
5245 | 0 | page_size = 1u <<lg2_page; |
5246 | 0 | page_mask = ~0ull<<lg2_page; |
5247 | |
|
5248 | 0 | progid = 0; // getRandomId(); not useful, so do not clutter |
5249 | 0 | sz_elf_hdrs = sizeof(ehdri) + sz_phdrs; |
5250 | | |
5251 | | // only execute if option present |
5252 | 0 | if (opt->o_unix.preserve_build_id) { |
5253 | | // set this so we can use elf_find_section_name |
5254 | 0 | e_shnum = get_te16(&ehdri.e_shnum); |
5255 | 0 | if (!shdri) { |
5256 | 0 | mb_shdr.alloc(e_shnum * sizeof(Elf64_Shdr)); |
5257 | 0 | shdri = (Elf64_Shdr *)mb_shdr.getVoidPtr(); |
5258 | 0 | e_shoff = get_te64(&ehdri.e_shoff); |
5259 | 0 | fi->seek(e_shoff, SEEK_SET); |
5260 | 0 | fi->readx(shdri, e_shnum * sizeof(Elf64_Shdr)); |
5261 | 0 | } |
5262 | | //set the shstrtab |
5263 | 0 | sec_strndx = &shdri[get_te16(&ehdri.e_shstrndx)]; |
5264 | |
|
5265 | 0 | upx_uint64_t sh_size = get_te64(&sec_strndx->sh_size); |
5266 | 0 | mb_shstrtab.alloc(sh_size); shstrtab = (char *)mb_shstrtab.getVoidPtr(); |
5267 | 0 | fi->seek(0,SEEK_SET); |
5268 | 0 | fi->seek(sec_strndx->sh_offset,SEEK_SET); |
5269 | 0 | fi->readx(mb_shstrtab, sh_size); |
5270 | |
|
5271 | 0 | Elf64_Shdr const *buildid = elf_find_section_name(".note.gnu.build-id"); |
5272 | 0 | if (buildid) { |
5273 | 0 | unsigned bid_sh_size = get_te64(&buildid->sh_size); // UPX_RSIZE_MAX_MEM protects us |
5274 | 0 | buildid_data.alloc(bid_sh_size); |
5275 | 0 | buildid_data.clear(); |
5276 | 0 | fi->seek(0,SEEK_SET); |
5277 | 0 | fi->seek(buildid->sh_offset,SEEK_SET); |
5278 | 0 | fi->readx((void *)buildid_data, bid_sh_size); |
5279 | |
|
5280 | 0 | o_elf_shnum = 3; |
5281 | 0 | memset(&shdrout,0,sizeof(shdrout)); |
5282 | | |
5283 | | //setup the build-id |
5284 | 0 | memcpy(&shdrout.shdr[1], buildid, sizeof(shdrout.shdr[1])); |
5285 | 0 | set_te32(&shdrout.shdr[1].sh_name, 1); |
5286 | | |
5287 | | //setup the shstrtab |
5288 | 0 | memcpy(&shdrout.shdr[2], sec_strndx, sizeof(shdrout.shdr[2])); |
5289 | 0 | set_te32(&shdrout.shdr[2].sh_name, 20); |
5290 | 0 | set_te64(&shdrout.shdr[2].sh_size, 29); //size of our static shstrtab; UPX_RSIZE_MAX_MEM |
5291 | 0 | } |
5292 | 0 | } |
5293 | 0 | } |
5294 | | |
5295 | | void PackLinuxElf64amd::pack1(OutputFile *fo, Filter &ft) |
5296 | 0 | { |
5297 | 0 | super::pack1(fo, ft); |
5298 | 0 | if (0!=xct_off) // shared library |
5299 | 0 | return; |
5300 | 0 | generateElfHdr(fo, stub_amd64_linux_elf_fold, getbrk(phdri, e_phnum) ); |
5301 | 0 | } |
5302 | | |
5303 | | void PackLinuxElf64arm::pack1(OutputFile *fo, Filter &ft) |
5304 | 0 | { |
5305 | 0 | super::pack1(fo, ft); |
5306 | 0 | if (0!=xct_off) // shared library |
5307 | 0 | return; |
5308 | 0 | generateElfHdr(fo, stub_arm64_linux_elf_fold, getbrk(phdri, e_phnum) ); |
5309 | 0 | } |
5310 | | |
5311 | | // Determine length of gap between PT_LOAD phdr[k] and closest PT_LOAD |
5312 | | // which follows in the file (or end-of-file). Optimize for common case |
5313 | | // where the PT_LOAD are adjacent ascending by .p_offset. Assume no overlap. |
5314 | | |
5315 | | unsigned PackLinuxElf32::find_LOAD_gap( |
5316 | | Elf32_Phdr const *const phdr, |
5317 | | unsigned const k, |
5318 | | unsigned const nph |
5319 | | ) |
5320 | 487 | { |
5321 | 487 | if (!is_LOAD(&phdr[k])) { |
5322 | 318 | return 0; |
5323 | 318 | } |
5324 | 169 | unsigned const hi = get_te32(&phdr[k].p_offset) + |
5325 | 169 | get_te32(&phdr[k].p_filesz); |
5326 | 169 | unsigned lo = ph.u_file_size; |
5327 | 169 | if (lo < hi) |
5328 | 0 | throwCantPack("bad input: PT_LOAD beyond end-of-file"); |
5329 | 169 | unsigned j = k; |
5330 | 1.04k | for (;;) { // circular search, optimize for adjacent ascending |
5331 | 1.04k | ++j; |
5332 | 1.04k | if (nph==j) { |
5333 | 153 | j = 0; |
5334 | 153 | } |
5335 | 1.04k | if (k==j) { |
5336 | 153 | break; |
5337 | 153 | } |
5338 | 888 | if (is_LOAD(&phdr[j])) { |
5339 | 265 | unsigned const t = get_te32(&phdr[j].p_offset); |
5340 | 265 | if ((t - hi) < (lo - hi)) { |
5341 | 109 | lo = t; |
5342 | 109 | if (hi==lo) { |
5343 | 16 | break; |
5344 | 16 | } |
5345 | 109 | } |
5346 | 265 | } |
5347 | 888 | } |
5348 | 169 | return lo - hi; |
5349 | 169 | } |
5350 | | |
5351 | | unsigned PackLinuxElf::pack2_shlib_overlay_init(OutputFile *fo) |
5352 | 0 | { |
5353 | 0 | linfo.l_checksum = 0; // preliminary |
5354 | 0 | linfo.l_magic = UPX_MAGIC_LE32; |
5355 | |
|
5356 | 0 | set_le16(&linfo.l_lsize, lsize); // preliminary (0) |
5357 | 0 | linfo.l_version = (unsigned char)ph.version; |
5358 | 0 | linfo.l_format = (unsigned char)ph.format; |
5359 | 0 | linfo_off = total_out; |
5360 | 0 | fo->write(&linfo, sizeof(linfo)); total_out += sizeof(linfo); |
5361 | |
|
5362 | 0 | overlay_offset = total_out; |
5363 | |
|
5364 | 0 | p_info hbuf; |
5365 | 0 | set_te32(&hbuf.p_progid, 0); |
5366 | 0 | set_te32(&hbuf.p_filesize, file_size); |
5367 | 0 | set_te32(&hbuf.p_blocksize, blocksize); |
5368 | 0 | fo->write(&hbuf, sizeof(hbuf)); total_out += sizeof(hbuf); |
5369 | 0 | return total_out; |
5370 | 0 | } |
5371 | | |
5372 | | unsigned PackLinuxElf::pack2_shlib_overlay_write(OutputFile *fo, MemBuffer &mb, |
5373 | | unsigned u_len, unsigned c_len) |
5374 | 0 | { |
5375 | | // Write mb with b_info header. |
5376 | 0 | b_info tmp; |
5377 | 0 | memset(&tmp, 0, sizeof(tmp)); |
5378 | 0 | set_te32(&tmp.sz_unc, u_len); |
5379 | 0 | set_te32(&tmp.sz_cpr, c_len); |
5380 | 0 | tmp.b_method = (EM_ARM == e_machine) ? M_NRV2B_8 : M_NRV2B_LE32; |
5381 | 0 | tmp.b_extra = 0; |
5382 | 0 | fo->write(&tmp, sizeof(tmp)); total_out += sizeof(tmp); |
5383 | 0 | b_len += sizeof(b_info); |
5384 | 0 | fo->write(mb, c_len); total_out += c_len; |
5385 | 0 | return total_out; |
5386 | 0 | } |
5387 | | |
5388 | | // Returns compressed size |
5389 | | unsigned PackLinuxElf::pack2_shlib_overlay_compress( |
5390 | | MemBuffer &bufo, |
5391 | | upx_byte const *inp, |
5392 | | unsigned u_len |
5393 | | ) |
5394 | 0 | { |
5395 | 0 | ph.saved_u_adler = ph.u_adler; |
5396 | 0 | ph.u_adler = upx_adler32(inp, u_len, ph.saved_u_adler); |
5397 | 0 | ph.u_len += u_len; |
5398 | |
|
5399 | 0 | unsigned const method = (EM_ARM == e_machine) ? M_NRV2B_8 : M_NRV2B_LE32; |
5400 | 0 | methods_used |= 1 << method; |
5401 | 0 | unsigned c_len = 0; |
5402 | 0 | int r = upx_compress(inp, u_len, bufo, &c_len, |
5403 | 0 | /* &progress callback */ nullptr, |
5404 | 0 | method, 10, |
5405 | 0 | /* &config_t */ nullptr, /* &result_t */ nullptr); |
5406 | 0 | if (r != UPX_E_OK) |
5407 | 0 | throwInternalError("header compression failed"); |
5408 | 0 | if (c_len >= u_len) |
5409 | 0 | throwInternalError("header compression size increase"); |
5410 | | |
5411 | 0 | ph.saved_c_adler = ph.c_adler; |
5412 | 0 | ph.c_adler = upx_adler32(bufo, c_len, ph.saved_c_adler); |
5413 | 0 | ph.c_len += c_len; |
5414 | 0 | return c_len; |
5415 | 0 | } |
5416 | | |
5417 | | // Layout for compressed shared library: |
5418 | | // 1. If first PT_LOAD is totally below xct_off |
5419 | | // (namely, (.p_memsz + .p_offset) <= xct_off ) |
5420 | | // then it must be Ehdr+Phdrs followed only by PT_DYNAMIC (Dynamic |
5421 | | // section) and loader tables (DT_* data), and the order of output is: |
5422 | | // A. original first PT_LOAD (Ehdr+Phdrs will be overwritten later) |
5423 | | // B. compressed Ehdr+Phdrs (for de-compressor to restore); M_NRV2B_LE32, no filter |
5424 | | // C. compressed remaining PT_LOAD segments (except PT_WRITE), |
5425 | | // regardless of xct_off. |
5426 | | // Until xct_off is covered by some PT_LOAD, then there is a logical |
5427 | | // two-pass problem. The best compression algorithm is not chosen |
5428 | | // until the PT_LOAD which contains xct_off, but before that |
5429 | | // compression is desired anyway for any preceding PT_LOAD. |
5430 | | // So use NRV2B for the "early" PT_LOADs, and do not use packExtent |
5431 | | // which calls compressWithFilters and also creates a loader. |
5432 | | // Instead, do the compression "by hand" explicitly using upx_compress |
5433 | | // and write(). This may require ELF2 multi-decompressor (NRV2B |
5434 | | // on the early PT_LOADs, then something better). |
5435 | | // |
5436 | | // Example input Program Headers: |
5437 | | // Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align |
5438 | | // LOAD 0x000000 0x00000000 0x00000000 0x003a4 0x003a4 R 0x1000 Elf hdrs, loader tables |
5439 | | // LOAD 0x001000 0x00001000 0x00001000 0x001d4 0x001d4 R E 0x1000 small code |
5440 | | // LOAD 0x002000 0x00002000 0x00002000 0x09d40 0x09d40 R 0x1000 large app consts |
5441 | | // LOAD 0x00bef0 0x0000cef0 0x0000cef0 0x00118 0x0011c RW 0x1000 writeable |
5442 | | // |
5443 | | // xct_off will have been increased artifically to point to |
5444 | | // the large compressable PT_LOAD (0x9d40==MemSiz), in order to avoid |
5445 | | // NotCompressable because the earlier PT_LOADs were too short (< 4KiB). |
5446 | | // 2. If the first PT_LOAD covers xct_off, then the order of output is: |
5447 | | // A. original Ehdr+Phdrs (overwritten later) |
5448 | | // B. other original content below xct_off [loader tables] |
5449 | | // C. compressed Ehdr+Phdrs (for de-compressor to restore); M_NRV2B_LE32, no filter. |
5450 | | // D. compressed content above xct_off in first PT_LOAD; |
5451 | | // use filter for executable code. |
5452 | | // E. compressed remaining PT_LOAD (except PT_WRITE); no filter. |
5453 | | // |
5454 | | |
5455 | | int PackLinuxElf32::pack2_shlib(OutputFile *fo, Filter &ft, unsigned pre_xct_top) |
5456 | 0 | { |
5457 | | // prepare to alter Phdrs and Shdrs |
5458 | 0 | lowmem.alloc(up8(xct_off + (!is_asl |
5459 | 0 | ? 0 |
5460 | 0 | : e_shnum * sizeof(Elf32_Shdr)))); |
5461 | 0 | memcpy(lowmem, file_image, xct_off); // android omits Shdr from copy now |
5462 | |
|
5463 | 0 | MemBuffer elf_buf; |
5464 | 0 | elf_buf.allocForCompression(sz_elf_hdrs); |
5465 | 0 | unsigned u_len = sz_elf_hdrs; |
5466 | 0 | unsigned c_len = pack2_shlib_overlay_compress(elf_buf, lowmem, u_len); |
5467 | |
|
5468 | 0 | int n_ptload = 0; |
5469 | 0 | Elf32_Phdr *phdr = &phdri[0]; |
5470 | 0 | for (unsigned k = 0; k < e_phnum; ++phdr, ++k) |
5471 | 0 | if (is_LOAD(phdr)) { |
5472 | 0 | unsigned p_offset = get_te32(&phdr->p_offset); |
5473 | 0 | unsigned p_filesz = get_te32(&phdr->p_filesz); |
5474 | 0 | if (!n_ptload) { // first PT_LOAD |
5475 | 0 | if (is_asl) { // Copy up to xct_off, then add 2nd copy of Shdrs |
5476 | 0 | asl_pack2_Shdrs(fo, pre_xct_top); |
5477 | 0 | } |
5478 | 0 | else { |
5479 | 0 | fo->write(&lowmem[p_offset], sz_elf_hdrs); total_out += sz_elf_hdrs; |
5480 | 0 | total_in += sz_elf_hdrs; |
5481 | 0 | fo->seek(sz_phdrx, SEEK_CUR); total_out += sz_phdrx; // leave space |
5482 | | |
5483 | | // Compare PackUnix::packExtent, especially "if (u_len)" . |
5484 | | // |
5485 | |
|
5486 | 0 | unsigned const hi_offset = umin(xct_off, p_filesz + p_offset); |
5487 | 0 | if (sz_elf_hdrs < hi_offset) { |
5488 | | // Loader tables in first PT_LOAD, and below xct_off. |
5489 | | // |
5490 | 0 | fo->write(&lowmem[sz_elf_hdrs], hi_offset - sz_elf_hdrs); total_out += hi_offset - sz_elf_hdrs; |
5491 | 0 | total_in += hi_offset - sz_elf_hdrs; |
5492 | 0 | Elf32_Phdr *lo_phdr = k + (Elf32_Phdr *)(1+ (Elf32_Ehdr *)&lowmem[0]); |
5493 | 0 | set_te32(&lo_phdr->p_flags, Elf32_Phdr::PF_X | get_te32(&lo_phdr->p_flags)); |
5494 | 0 | } |
5495 | 0 | } |
5496 | 0 | pack2_shlib_overlay_init(fo); // set overlay_offset |
5497 | | // Compressed ELF headers go first. |
5498 | 0 | pack2_shlib_overlay_write(fo, elf_buf, u_len, c_len); |
5499 | | |
5500 | | // The (compressible) remainder above xct_off in first PT_LOAD |
5501 | 0 | if ( p_filesz > (xct_off - p_offset)) { |
5502 | 0 | Extent x; |
5503 | 0 | x.size = p_filesz - (xct_off - p_offset); |
5504 | 0 | x.offset = xct_off; |
5505 | 0 | packExtent(x, &ft, fo, 0, 0, true); |
5506 | 0 | } |
5507 | 0 | } // end first PT_LOAD |
5508 | 0 | else if ((p_filesz + p_offset) <= xct_off) { |
5509 | | // Not first PT_LOAD, but below xct_offset. Thus "interloper" PT_LOAD, |
5510 | | // below xct_off that was increased to a PT_LOAD large enough to compress. |
5511 | | // "Manually" compress it, do not use PackExtent. |
5512 | 0 | MemBuffer buf2; buf2.allocForCompression(p_filesz); |
5513 | 0 | c_len = pack2_shlib_overlay_compress(buf2, &lowmem[p_offset], p_filesz); total_in += p_filesz; |
5514 | 0 | pack2_shlib_overlay_write(fo, buf2, p_filesz, c_len); |
5515 | 0 | Elf32_Phdr *lo_phdr = k + (Elf32_Phdr *)(1+ (Elf32_Ehdr *)&lowmem[0]); |
5516 | 0 | set_te32(&lo_phdr->p_type, Elf32_Phdr::PT_NULL); |
5517 | 0 | } |
5518 | 0 | else if ((xct_off - p_offset) < p_filesz) { |
5519 | 0 | unsigned const len = xct_off - p_offset; |
5520 | | // Loader tables in non-first PT_LOAD. (xct_off was increased.) |
5521 | | // Bytes below xct_off belong to rtld, so cannot be compressed. |
5522 | | // Note that asl_pack2_Shdrs() copies up to xct_off, then adds extra info. |
5523 | | // Copy up to xct_off |
5524 | 0 | if (len) { |
5525 | 0 | fo->write(&lowmem[p_offset], len); total_out += len; |
5526 | 0 | total_in += len; |
5527 | | |
5528 | | // Compressed ELF headers FIXME: 1st PT_LOAD also did this! |
5529 | 0 | pack2_shlib_overlay_write(fo, elf_buf, u_len, c_len); // set overlay_offset |
5530 | 0 | } |
5531 | | // The rest, above xct_off. |
5532 | 0 | Extent x; |
5533 | 0 | x.offset = xct_off; |
5534 | 0 | x.size = p_filesz - len; |
5535 | 0 | packExtent(x, &ft, fo, 0, 0, true); |
5536 | 0 | Elf32_Phdr *lo_phdr = k + (Elf32_Phdr *)(1+ (Elf32_Ehdr *)&lowmem[0]); |
5537 | 0 | set_te32(&lo_phdr->p_type, Elf32_Phdr::PT_NULL); |
5538 | 0 | } |
5539 | 0 | else { // definitely compressible unless writeable |
5540 | 0 | if (!(Elf32_Phdr::PF_W & get_te32(&phdr->p_flags))) { |
5541 | | // Read-only PT_LOAD, assume not written by relocations. |
5542 | | // Also assume not the source for R_*_COPY relocation, |
5543 | | // therefore compress it. |
5544 | 0 | Extent x; |
5545 | 0 | x.offset = p_offset; |
5546 | 0 | x.size = p_filesz; |
5547 | 0 | packExtent(x, &ft, fo, 0, 0, true); // choose filter and method, then do it |
5548 | | // De-compressing will re-create it, but otherwise ignore it. |
5549 | 0 | Elf32_Phdr *phdro = (Elf32_Phdr *)(1+ (Elf32_Ehdr *)&lowmem[0]); |
5550 | 0 | set_te32(&phdro[k].p_type, Elf32_Phdr::PT_NULL); |
5551 | 0 | } |
5552 | 0 | else { |
5553 | | // Read-write PT_LOAD. |
5554 | | // rtld might relocate, so we cannot compress. |
5555 | | // (Could compress if not relocated; complicates run-time.) |
5556 | | // Postpone writing until "slide", but account for its size. |
5557 | 0 | total_in += p_filesz; |
5558 | 0 | } |
5559 | 0 | } |
5560 | 0 | ++n_ptload; |
5561 | 0 | } |
5562 | 0 | return 0; // FIXME |
5563 | 0 | } |
5564 | | |
5565 | | int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft) |
5566 | 0 | { |
5567 | 0 | Extent x; |
5568 | 0 | unsigned k; |
5569 | 0 | unsigned const is_shlib = (0!=xct_off) | is_asl; |
5570 | 0 | unsigned pre_xct_top = 0; // offset of end of PT_LOAD _before_ xct_off |
5571 | | |
5572 | | // count passes, set ptload vars |
5573 | 0 | uip->ui_total_passes = 0; |
5574 | 0 | for (k = 0; k < e_phnum; ++k) { |
5575 | 0 | if (is_LOAD(&phdri[k])) { |
5576 | 0 | if (!is_shlib) { |
5577 | 0 | uip->ui_total_passes++; |
5578 | 0 | } |
5579 | 0 | else { |
5580 | 0 | unsigned p_flags = get_te32(&phdri[k].p_flags); |
5581 | 0 | unsigned p_offset = get_te32(&phdri[k].p_offset); |
5582 | 0 | unsigned p_filesz = get_te32(&phdri[k].p_filesz); |
5583 | 0 | if ((xct_off - p_offset) < p_filesz) { // PT_LOAD covers xct_off |
5584 | 0 | if (!pre_xct_top && xct_off != p_offset) { |
5585 | 0 | pre_xct_top = xct_off; |
5586 | 0 | } |
5587 | 0 | } |
5588 | 0 | else if (p_offset < xct_off) { // candidate for pre_xct_top |
5589 | 0 | unsigned top = p_filesz + p_offset; |
5590 | 0 | if (pre_xct_top < top) { |
5591 | 0 | pre_xct_top = top; |
5592 | 0 | } |
5593 | 0 | } |
5594 | 0 | if (Elf32_Phdr::PF_W & p_flags) { |
5595 | | // rtld might write, so cannot compress |
5596 | 0 | } |
5597 | 0 | else { |
5598 | | // First PT_LOAD (partial) only if has instructions |
5599 | 0 | if (k || xct_off < p_filesz) { |
5600 | 0 | uip->ui_total_passes++; |
5601 | 0 | } |
5602 | 0 | } |
5603 | 0 | } |
5604 | 0 | if (find_LOAD_gap(phdri, k, e_phnum)) { |
5605 | 0 | uip->ui_total_passes++; |
5606 | 0 | } |
5607 | 0 | } |
5608 | 0 | } |
5609 | | |
5610 | | // compress extents |
5611 | 0 | unsigned hdr_u_len = sizeof(Elf32_Ehdr) + sz_phdrs; |
5612 | |
|
5613 | 0 | total_in = 0; |
5614 | 0 | total_out = 0; |
5615 | 0 | uip->ui_pass = 0; |
5616 | 0 | ft.addvalue = 0; |
5617 | |
|
5618 | 0 | unsigned nk_f = 0; upx_uint32_t xsz_f = 0; |
5619 | 0 | for (k = 0; k < e_phnum; ++k) |
5620 | 0 | if (is_LOAD(&phdri[k]) |
5621 | 0 | && Elf32_Phdr::PF_X & get_te32(&phdri[k].p_flags)) { |
5622 | 0 | upx_uint32_t xsz = get_te32(&phdri[k].p_filesz); |
5623 | 0 | if (xsz_f < xsz) { |
5624 | 0 | xsz_f = xsz; |
5625 | 0 | nk_f = k; |
5626 | 0 | } |
5627 | 0 | } |
5628 | 0 | if (is_shlib) { |
5629 | 0 | pack2_shlib(fo, ft, pre_xct_top); |
5630 | 0 | } |
5631 | 0 | else { // main program |
5632 | 0 | int n_ptload = 0; |
5633 | 0 | for (k = 0; k < e_phnum; ++k) |
5634 | 0 | if (is_LOAD(&phdri[k])) { |
5635 | 0 | if (ft.id < 0x40) { |
5636 | | // FIXME: ?? ft.addvalue = phdri[k].p_vaddr; |
5637 | 0 | } |
5638 | 0 | unsigned p_offset = get_te32(&phdri[k].p_offset); |
5639 | 0 | unsigned p_filesz = get_te32(&phdri[k].p_filesz); |
5640 | 0 | x.offset = p_offset; |
5641 | 0 | x.size = p_filesz; |
5642 | 0 | if ((u32_t)x.size < hdr_u_len) { // FIXME: main program, but how? |
5643 | 0 | total_in += x.size; |
5644 | 0 | } |
5645 | 0 | else { // main program, not shared library |
5646 | 0 | if (0 == n_ptload) { // 1st PT_LOAD must cover Ehdr at 0==p_offset |
5647 | 0 | unsigned const delta = hdr_u_len; |
5648 | 0 | if (ft.id < 0x40) { |
5649 | | // FIXME: ?? ft.addvalue += asl_delta; |
5650 | 0 | } |
5651 | 0 | if ((off_t)delta == x.size) { // PT_LOAD[0] with ElfXX.Ehdr only |
5652 | | // QBE backend - http://c9x.me/compile/ |
5653 | 0 | hdr_u_len = 0; // no fiddling necessary! |
5654 | | // &ft arg to packExtent will be zero because (k != nk_f) |
5655 | 0 | } |
5656 | 0 | else { |
5657 | 0 | total_in += delta - hdr_u_len; |
5658 | 0 | x.offset += delta; |
5659 | 0 | x.size -= delta; |
5660 | 0 | } |
5661 | 0 | } |
5662 | | // compressWithFilters() always assumes a "loader", so would |
5663 | | // throw NotCompressible for small .data Extents, which PowerPC |
5664 | | // sometimes marks as PF_X anyway. So filter only first segment. |
5665 | 0 | packExtent(x, |
5666 | 0 | (k==nk_f ? &ft : nullptr ), fo, hdr_u_len, 0, true); |
5667 | 0 | hdr_u_len = 0; |
5668 | 0 | } |
5669 | 0 | ++n_ptload; |
5670 | 0 | } |
5671 | 0 | } |
5672 | 0 | sz_pack2a = fpad4(fo, total_out); // MATCH01 |
5673 | 0 | total_out = up4(total_out); |
5674 | | |
5675 | | // Accounting only; ::pack3 will do the compression and output |
5676 | 0 | for (k = 0; k < e_phnum; ++k) { |
5677 | 0 | total_in += find_LOAD_gap(phdri, k, e_phnum); |
5678 | 0 | } |
5679 | |
|
5680 | 0 | if (total_in != (u32_t)file_size) |
5681 | 0 | throwEOFException(); |
5682 | | |
5683 | 0 | return 0; // omit end-of-compression bhdr for now |
5684 | 0 | } |
5685 | | |
5686 | | // Determine length of gap between PT_LOAD phdr[k] and closest PT_LOAD |
5687 | | // which follows in the file (or end-of-file). Optimize for common case |
5688 | | // where the PT_LOAD are adjacent ascending by .p_offset. Assume no overlap. |
5689 | | |
5690 | | unsigned PackLinuxElf64::find_LOAD_gap( |
5691 | | Elf64_Phdr const *const phdr, |
5692 | | unsigned const k, |
5693 | | unsigned const nph |
5694 | | ) |
5695 | 749 | { |
5696 | 749 | if (!is_LOAD(&phdr[k])) { |
5697 | 530 | return 0; |
5698 | 530 | } |
5699 | 219 | unsigned const hi = get_te64(&phdr[k].p_offset) + |
5700 | 219 | get_te64(&phdr[k].p_filesz); |
5701 | 219 | unsigned lo = ph.u_file_size; |
5702 | 219 | if (lo < hi) |
5703 | 0 | throwCantPack("bad input: PT_LOAD beyond end-of-file"); |
5704 | 219 | unsigned j = k; |
5705 | 1.46k | for (;;) { // circular search, optimize for adjacent ascending |
5706 | 1.46k | ++j; |
5707 | 1.46k | if (nph==j) { |
5708 | 213 | j = 0; |
5709 | 213 | } |
5710 | 1.46k | if (k==j) { |
5711 | 213 | break; |
5712 | 213 | } |
5713 | 1.25k | if (is_LOAD(&phdr[j])) { |
5714 | 411 | unsigned const t = get_te64(&phdr[j].p_offset); |
5715 | 411 | if ((t - hi) < (lo - hi)) { |
5716 | 154 | lo = t; |
5717 | 154 | if (hi==lo) { |
5718 | 6 | break; |
5719 | 6 | } |
5720 | 154 | } |
5721 | 411 | } |
5722 | 1.25k | } |
5723 | 219 | return lo - hi; |
5724 | 219 | } |
5725 | | |
5726 | | int PackLinuxElf64::pack2_shlib(OutputFile *fo, Filter &ft, unsigned pre_xct_top) |
5727 | 0 | { |
5728 | | // prepare to alter Phdrs and Shdrs |
5729 | 0 | lowmem.alloc(up8(xct_off + (!is_asl |
5730 | 0 | ? 0 |
5731 | 0 | : e_shnum * sizeof(Elf64_Shdr)))); |
5732 | 0 | memcpy(lowmem, file_image, xct_off); // android omits Shdr from copy now |
5733 | |
|
5734 | 0 | MemBuffer elf_buf; |
5735 | 0 | elf_buf.allocForCompression(sz_elf_hdrs); |
5736 | 0 | unsigned u_len = sz_elf_hdrs; |
5737 | 0 | unsigned c_len = pack2_shlib_overlay_compress(elf_buf, lowmem, u_len); |
5738 | |
|
5739 | 0 | int n_ptload = 0; |
5740 | 0 | Elf64_Phdr *phdr = &phdri[0]; |
5741 | 0 | for (unsigned k = 0; k < e_phnum; ++phdr, ++k) |
5742 | 0 | if (is_LOAD(phdr)) { |
5743 | 0 | unsigned p_offset = get_te64_32(&phdr->p_offset); |
5744 | 0 | unsigned p_filesz = get_te64_32(&phdr->p_filesz); |
5745 | 0 | if (!n_ptload) { // first PT_LOAD |
5746 | 0 | if (is_asl) { // Copy up to xct_off, then add 2nd copy of Shdrs |
5747 | 0 | asl_pack2_Shdrs(fo, pre_xct_top); |
5748 | 0 | } |
5749 | 0 | else { |
5750 | 0 | fo->write(&lowmem[p_offset], sz_elf_hdrs); total_out += sz_elf_hdrs; |
5751 | 0 | total_in += sz_elf_hdrs; |
5752 | 0 | fo->seek(sz_phdrx, SEEK_CUR); total_out += sz_phdrx; // leave space |
5753 | | |
5754 | | // Compare PackUnix::packExtent, especially "if (u_len)" . |
5755 | | // |
5756 | |
|
5757 | 0 | unsigned const hi_offset = umin(xct_off, (unsigned)(p_filesz + p_offset)); |
5758 | 0 | if (sz_elf_hdrs < hi_offset) { |
5759 | | // Loader tables in first PT_LOAD, and below xct_off. |
5760 | | // |
5761 | 0 | fo->write(&lowmem[sz_elf_hdrs], hi_offset - sz_elf_hdrs); total_out += hi_offset - sz_elf_hdrs; |
5762 | 0 | total_in += hi_offset - sz_elf_hdrs; |
5763 | 0 | Elf64_Phdr *lo_phdr = k + (Elf64_Phdr *)(1+ (Elf64_Ehdr *)&lowmem[0]); |
5764 | 0 | set_te32(&lo_phdr->p_flags, Elf64_Phdr::PF_X | get_te32(&lo_phdr->p_flags)); |
5765 | 0 | } |
5766 | 0 | } |
5767 | 0 | pack2_shlib_overlay_init(fo); // set overlay_offset |
5768 | | // Compressed ELF headers go first. |
5769 | 0 | pack2_shlib_overlay_write(fo, elf_buf, u_len, c_len); |
5770 | | |
5771 | | // The (compressible) remainder above xct_off in first PT_LOAD |
5772 | 0 | if ( p_filesz > (xct_off - p_offset)) { |
5773 | 0 | Extent x; |
5774 | 0 | x.size = p_filesz - (xct_off - p_offset); |
5775 | 0 | x.offset = xct_off; |
5776 | 0 | packExtent(x, &ft, fo, 0, 0, true); |
5777 | 0 | } |
5778 | 0 | } // end first PT_LOAD |
5779 | 0 | else if ((p_filesz + p_offset) <= xct_off) { |
5780 | | // Not first PT_LOAD, but below xct_offset. Thus "interloper" PT_LOAD, |
5781 | | // below xct_off that was increased to a PT_LOAD large enough to compress. |
5782 | | // "Manually" compress it, do not use PackExtent. |
5783 | 0 | MemBuffer buf2; buf2.allocForCompression(p_filesz); |
5784 | 0 | c_len = pack2_shlib_overlay_compress(buf2, &lowmem[p_offset], p_filesz); total_in += p_filesz; |
5785 | 0 | pack2_shlib_overlay_write(fo, buf2, p_filesz, c_len); |
5786 | 0 | Elf64_Phdr *lo_phdr = k + (Elf64_Phdr *)(1+ (Elf64_Ehdr *)&lowmem[0]); |
5787 | 0 | set_te32(&lo_phdr->p_type, Elf64_Phdr::PT_NULL); |
5788 | 0 | } |
5789 | 0 | else if ((xct_off - p_offset) < p_filesz) { |
5790 | 0 | unsigned const len = xct_off - p_offset; |
5791 | | // Loader tables in non-first PT_LOAD. (xct_off was increased.) |
5792 | | // Bytes below xct_off belong to rtld, so cannot be compressed. |
5793 | | // Note that asl_pack2_Shdrs() copies up to xct_off, then adds extra info. |
5794 | | // Copy up to xct_off |
5795 | 0 | if (len) { |
5796 | 0 | fo->write(&lowmem[p_offset], len); total_out += len; |
5797 | 0 | total_in += len; |
5798 | | |
5799 | | // Compressed ELF headers FIXME: 1st PT_LOAD also did this! |
5800 | 0 | pack2_shlib_overlay_write(fo, elf_buf, u_len, c_len); // set overlay_offset |
5801 | 0 | } |
5802 | | // The rest, above xct_off. |
5803 | 0 | Extent x; |
5804 | 0 | x.offset = xct_off; |
5805 | 0 | x.size = p_filesz - len; |
5806 | 0 | packExtent(x, &ft, fo, 0, 0, true); |
5807 | 0 | Elf64_Phdr *lo_phdr = k + (Elf64_Phdr *)(1+ (Elf64_Ehdr *)&lowmem[0]); |
5808 | 0 | set_te32(&lo_phdr->p_type, Elf64_Phdr::PT_NULL); |
5809 | 0 | } |
5810 | 0 | else { // definitely compressible unless writeable |
5811 | 0 | if (!(Elf64_Phdr::PF_W & get_te32(&phdr->p_flags))) { |
5812 | | // Read-only PT_LOAD, assume not written by relocations. |
5813 | | // Also assume not the source for R_*_COPY relocation, |
5814 | | // therefore compress it. |
5815 | 0 | Extent x; |
5816 | 0 | x.offset = p_offset; |
5817 | 0 | x.size = p_filesz; |
5818 | 0 | packExtent(x, &ft, fo, 0, 0, true); // choose filter and method, then do it |
5819 | | // De-compressing will re-create it, but otherwise ignore it. |
5820 | 0 | Elf64_Phdr *phdro = (Elf64_Phdr *)(1+ (Elf64_Ehdr *)&lowmem[0]); |
5821 | 0 | set_te32(&phdro[k].p_type, Elf32_Phdr::PT_NULL); |
5822 | 0 | } |
5823 | 0 | else { |
5824 | | // Read-write PT_LOAD. |
5825 | | // rtld might relocate, so we cannot compress. |
5826 | | // (Could compress if not relocated; complicates run-time.) |
5827 | | // Postpone writing until "slide", but account for its size. |
5828 | 0 | total_in += p_filesz; |
5829 | 0 | } |
5830 | 0 | } |
5831 | 0 | ++n_ptload; |
5832 | 0 | } |
5833 | 0 | return 0; // FIXME |
5834 | 0 | } |
5835 | | |
5836 | | int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft) |
5837 | 0 | { |
5838 | 0 | Extent x; |
5839 | 0 | unsigned k; |
5840 | | // See comment in Elf32_Linux::canPack(). is_asl does not work. |
5841 | | // 64-bit ARM (aarch64) also has no ARM_ATTRIBUTES. |
5842 | | //is_asl = (!!saved_opt_android_shlib) << 1; // bit 1; see is_shlib |
5843 | 0 | is_asl = 0; |
5844 | 0 | unsigned const is_shlib = (0!=xct_off) | is_asl; |
5845 | 0 | unsigned pre_xct_top = 0; // offset of end of PT_LOAD _before_ xct_off |
5846 | |
|
5847 | 0 | if (Elf64_Ehdr::EM_ARM==get_te16(&ehdri.e_machine)) { |
5848 | 0 | sec_arm_attr = elf_find_section_type(Elf64_Shdr::SHT_ARM_ATTRIBUTES); |
5849 | 0 | } |
5850 | | // count passes, set ptload vars |
5851 | 0 | uip->ui_total_passes = 0; |
5852 | 0 | for (k = 0; k < e_phnum; ++k) { |
5853 | 0 | if (is_LOAD(&phdri[k])) { |
5854 | 0 | if (!is_shlib) { |
5855 | 0 | uip->ui_total_passes++; |
5856 | 0 | } |
5857 | 0 | else { |
5858 | 0 | unsigned p_flags = get_te32(&phdri[k].p_flags); |
5859 | 0 | unsigned p_offset = get_te64_32(&phdri[k].p_offset); |
5860 | 0 | unsigned p_filesz = get_te64_32(&phdri[k].p_filesz); |
5861 | 0 | if ((xct_off - p_offset) < p_filesz) { // PT_LOAD covers xct_off |
5862 | 0 | if (!pre_xct_top && xct_off != p_offset) { |
5863 | 0 | pre_xct_top = xct_off; |
5864 | 0 | } |
5865 | 0 | } |
5866 | 0 | else if (p_offset < xct_off) { // candidate for pre_xct_top |
5867 | 0 | unsigned top = p_filesz + p_offset; |
5868 | 0 | if (pre_xct_top < top) { |
5869 | 0 | pre_xct_top = top; |
5870 | 0 | } |
5871 | 0 | } |
5872 | 0 | if (Elf64_Phdr::PF_W & p_flags) { |
5873 | | // rtld might write, so cannot compress |
5874 | 0 | } |
5875 | 0 | else { |
5876 | | // First PT_LOAD (partial) only if has instructions |
5877 | 0 | if (k || xct_off < p_filesz) { |
5878 | 0 | uip->ui_total_passes++; |
5879 | 0 | } |
5880 | 0 | } |
5881 | 0 | } |
5882 | 0 | if (find_LOAD_gap(phdri, k, e_phnum)) { |
5883 | 0 | uip->ui_total_passes++; |
5884 | 0 | } |
5885 | 0 | } |
5886 | 0 | } |
5887 | | |
5888 | | // compress extents |
5889 | 0 | unsigned hdr_u_len = sizeof(Elf64_Ehdr) + sz_phdrs; |
5890 | |
|
5891 | 0 | total_in = 0; |
5892 | 0 | total_out = 0; |
5893 | 0 | uip->ui_pass = 0; |
5894 | 0 | ft.addvalue = 0; |
5895 | |
|
5896 | 0 | unsigned nk_f = 0; upx_uint32_t xsz_f = 0; |
5897 | 0 | for (k = 0; k < e_phnum; ++k) |
5898 | 0 | if (is_LOAD(&phdri[k]) |
5899 | 0 | && Elf32_Phdr::PF_X & get_te32(&phdri[k].p_flags)) { |
5900 | 0 | unsigned xsz = get_te64_32(&phdri[k].p_filesz); |
5901 | 0 | if (xsz_f < xsz) { |
5902 | 0 | xsz_f = xsz; |
5903 | 0 | nk_f = k; |
5904 | 0 | } |
5905 | 0 | } |
5906 | 0 | if (is_shlib) { |
5907 | 0 | pack2_shlib(fo, ft, pre_xct_top); |
5908 | 0 | } |
5909 | 0 | else { // main program |
5910 | 0 | int n_ptload = 0; |
5911 | 0 | for (k = 0; k < e_phnum; ++k) |
5912 | 0 | if (is_LOAD(&phdri[k])) { |
5913 | 0 | if (ft.id < 0x40) { |
5914 | | // FIXME: ?? ft.addvalue = phdri[k].p_vaddr; |
5915 | 0 | } |
5916 | 0 | unsigned p_offset = get_te64_32(&phdri[k].p_offset); |
5917 | 0 | unsigned p_filesz = get_te64_32(&phdri[k].p_filesz); |
5918 | 0 | x.offset = p_offset; |
5919 | 0 | x.size = p_filesz; |
5920 | 0 | if ((u32_t)x.size < hdr_u_len) { // FIXME: main program, but how? |
5921 | 0 | total_in += x.size; |
5922 | 0 | } |
5923 | 0 | else { // main program, not shared library |
5924 | 0 | if (0 == n_ptload) { // 1st PT_LOAD must cover Ehdr at 0==p_offset |
5925 | 0 | unsigned const delta = hdr_u_len; |
5926 | 0 | if (ft.id < 0x40) { |
5927 | | // FIXME: ?? ft.addvalue += asl_delta; |
5928 | 0 | } |
5929 | 0 | if ((off_t)delta == x.size) { // PT_LOAD[0] with ElfXX.Ehdr only |
5930 | | // QBE backend - http://c9x.me/compile/ |
5931 | 0 | hdr_u_len = 0; // no fiddling necessary! |
5932 | | // &ft arg to packExtent will be zero because (k != nk_f) |
5933 | 0 | } |
5934 | 0 | else { |
5935 | 0 | total_in += delta - hdr_u_len; |
5936 | 0 | x.offset += delta; |
5937 | 0 | x.size -= delta; |
5938 | 0 | } |
5939 | 0 | } |
5940 | | // compressWithFilters() always assumes a "loader", so would |
5941 | | // throw NotCompressible for small .data Extents, which PowerPC |
5942 | | // sometimes marks as PF_X anyway. So filter only first segment. |
5943 | 0 | packExtent(x, |
5944 | 0 | (k==nk_f ? &ft : nullptr ), fo, hdr_u_len, 0, true); |
5945 | 0 | hdr_u_len = 0; |
5946 | 0 | } |
5947 | 0 | ++n_ptload; |
5948 | 0 | } |
5949 | 0 | } |
5950 | 0 | sz_pack2a = fpad4(fo, total_out); // MATCH01 |
5951 | 0 | total_out = up4(total_out); |
5952 | | |
5953 | | // Accounting only; ::pack3 will do the compression and output |
5954 | 0 | for (k = 0; k < e_phnum; ++k) { |
5955 | 0 | total_in += find_LOAD_gap(phdri, k, e_phnum); |
5956 | 0 | } |
5957 | |
|
5958 | 0 | if (total_in != (u32_t)file_size) |
5959 | 0 | throwEOFException(); |
5960 | | |
5961 | 0 | return 0; // omit end-of-compression bhdr for now |
5962 | 0 | } |
5963 | | |
5964 | | // Filter 0x50, 0x51 assume HostPolicy::isLE |
5965 | | static const int * |
5966 | | ARM_getFilters(bool const isBE) |
5967 | 0 | { |
5968 | 0 | static const int f50[] = { 0x50, FT_END }; |
5969 | 0 | static const int f51[] = { 0x51, FT_END }; |
5970 | 0 | if (isBE) |
5971 | 0 | return f51; |
5972 | 0 | return f50; |
5973 | 0 | } |
5974 | | |
5975 | | const int * |
5976 | | PackLinuxElf32armBe::getFilters() const |
5977 | 0 | { |
5978 | 0 | return ARM_getFilters(true); |
5979 | 0 | } |
5980 | | |
5981 | | const int * |
5982 | | PackLinuxElf32armLe::getFilters() const |
5983 | 0 | { |
5984 | 0 | return ARM_getFilters(false); |
5985 | 0 | } |
5986 | | |
5987 | | const int * |
5988 | | PackLinuxElf32mipseb::getFilters() const |
5989 | 0 | { |
5990 | 0 | static const int f_none[] = { FT_END }; |
5991 | 0 | return f_none; |
5992 | 0 | } |
5993 | | |
5994 | | const int * |
5995 | | PackLinuxElf32mipsel::getFilters() const |
5996 | 0 | { |
5997 | 0 | static const int f_none[] = { FT_END }; |
5998 | 0 | return f_none; |
5999 | 0 | } |
6000 | | |
6001 | | // October 2011: QNX 6.3.0 has no unique signature? |
6002 | | int PackLinuxElf32::ARM_is_QNX(void) |
6003 | 0 | { |
6004 | 0 | if (Elf32_Ehdr::EM_ARM==get_te16(&ehdri.e_machine) |
6005 | 0 | && Elf32_Ehdr::ELFDATA2MSB== ehdri.e_ident[Elf32_Ehdr::EI_DATA] |
6006 | 0 | && Elf32_Ehdr::ELFOSABI_ARM==ehdri.e_ident[Elf32_Ehdr::EI_OSABI] |
6007 | 0 | && 0x100000==(page_mask & get_te32(&phdri[0].p_vaddr))) { |
6008 | 0 | Elf32_Phdr const *phdr = phdri; |
6009 | 0 | for (int j = get_te16(&ehdri.e_phnum); --j>=0; ++phdr) { |
6010 | 0 | if (Elf32_Phdr::PT_INTERP==get_te32(&phdr->p_type)) { |
6011 | 0 | char interp[64]; |
6012 | 0 | unsigned const sz_interp = get_te32(&phdr->p_filesz); |
6013 | 0 | unsigned const pos_interp = get_te32(&phdr->p_offset); |
6014 | 0 | if (sz_interp <= sizeof(interp) |
6015 | 0 | && (sz_interp + pos_interp) <= (unsigned)file_size) { |
6016 | 0 | fi->seek(pos_interp, SEEK_SET); |
6017 | 0 | fi->readx(interp, sz_interp); |
6018 | 0 | for (int k = sz_interp - 5; k>=0; --k) { |
6019 | 0 | if (0==memcmp("ldqnx", &interp[k], 5)) |
6020 | 0 | return 1; |
6021 | 0 | } |
6022 | 0 | } |
6023 | 0 | } |
6024 | 0 | } |
6025 | 0 | } |
6026 | 0 | return 0; |
6027 | 0 | } |
6028 | | |
6029 | | void PackLinuxElf32::ARM_defineSymbols(Filter const *ft) |
6030 | 0 | { |
6031 | 0 | PackLinuxElf32::defineSymbols(ft); |
6032 | |
|
6033 | 0 | #define MAP_PRIVATE 2 /* UNIX standard */ |
6034 | 0 | #define MAP_FIXED 0x10 /* UNIX standard */ |
6035 | 0 | #define MAP_ANONYMOUS 0x20 /* UNIX standard */ |
6036 | 0 | #define MAP_PRIVANON 3 /* QNX anonymous private memory */ |
6037 | 0 | unsigned mflg = MAP_PRIVATE | MAP_ANONYMOUS; |
6038 | 0 | if (ARM_is_QNX()) |
6039 | 0 | mflg = MAP_PRIVANON; |
6040 | 0 | linker->defineSymbol("MFLG", mflg); |
6041 | 0 | } |
6042 | | |
6043 | | void PackLinuxElf32armLe::defineSymbols(Filter const *ft) |
6044 | 0 | { |
6045 | 0 | ARM_defineSymbols(ft); |
6046 | 0 | } |
6047 | | |
6048 | | void PackLinuxElf32armBe::defineSymbols(Filter const *ft) |
6049 | 0 | { |
6050 | 0 | ARM_defineSymbols(ft); |
6051 | 0 | } |
6052 | | |
6053 | | void PackLinuxElf64arm::defineSymbols(Filter const *ft) |
6054 | 0 | { |
6055 | 0 | PackLinuxElf64::defineSymbols(ft); |
6056 | |
|
6057 | 0 | #define MAP_PRIVATE 2 /* UNIX standard */ |
6058 | 0 | #define MAP_FIXED 0x10 /* UNIX standard */ |
6059 | 0 | #define MAP_ANONYMOUS 0x20 /* UNIX standard */ |
6060 | 0 | #define MAP_PRIVANON 3 /* QNX anonymous private memory */ |
6061 | 0 | unsigned mflg = MAP_PRIVATE | MAP_ANONYMOUS; |
6062 | | //if (ARM_is_QNX()) |
6063 | | // mflg = MAP_PRIVANON; |
6064 | 0 | linker->defineSymbol("MFLG", mflg); |
6065 | 0 | } |
6066 | | |
6067 | | void PackLinuxElf32mipseb::defineSymbols(Filter const *ft) |
6068 | 0 | { |
6069 | 0 | PackLinuxElf32::defineSymbols(ft); |
6070 | 0 | } |
6071 | | |
6072 | | void PackLinuxElf32mipsel::defineSymbols(Filter const *ft) |
6073 | 0 | { |
6074 | 0 | PackLinuxElf32::defineSymbols(ft); |
6075 | 0 | } |
6076 | | |
6077 | | // ::forward_Shdrs adds info for the benefit of gdb and Android dlopen(). |
6078 | | // De-compression (runtime and offline) ignores the added information |
6079 | | // because it uses the de-compressed Ehdr etc. |
6080 | | // All the added space is redundant; libbfd should take a hint: |
6081 | | // if no Shdrs, then use PT_DYNAMIC instead. |
6082 | | // (.ARM_attributes (ARM_ATTRIBUTES) is not redundant.) |
6083 | | // |
6084 | | // want_types_mask: SHT_PROGBITS is needed else gdb complains: |
6085 | | // /build/gdb-MVZsgD/gdb-10.1/gdb/symfile.c:878: internal-error: sect_index_text not initialized |
6086 | | // and Continuing is not reasonable. |
6087 | | // However, SHT_PROGBITS with compression gives: |
6088 | | // BFD: warning: ./libmain.so.upx has a section extending past end of file |
6089 | | // BFD: warning: ./libmain.so.upx has a section extending past end of file |
6090 | | // BFD: warning: ./libmain.so.upx has a section extending past end of file |
6091 | | // warning: Loadable section ".text" outside of ELF segments |
6092 | | // warning: Loadable section ".plt" outside of ELF segments |
6093 | | // because compression gives smaller extents, with no reasonable _Shdr fields. |
6094 | | // At least gdb can continue. |
6095 | | |
6096 | | unsigned PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho) |
6097 | 0 | { |
6098 | 0 | if (!fo) { |
6099 | 0 | return 0; |
6100 | 0 | } |
6101 | 0 | unsigned penalty = total_out; |
6102 | 0 | if (sec_arm_attr) { // Forward select _Shdr. EM_ARM (and Android ?) only. |
6103 | | // Keep _Shdr for rtld data (below xct_off). |
6104 | | // Discard _Shdr for compressed regions, except ".text" for gdb. |
6105 | | // Keep _Shdr for SHF_WRITE. |
6106 | | // Discard _Shdr with (0==sh_addr), except _Shdr[0] |
6107 | | // Keep ARM_ATTRIBUTES |
6108 | 0 | unsigned const want_types_mask = 0 |
6109 | 0 | | 1u<<SHT_PROGBITS // see comment above, and special code below |
6110 | 0 | | 1u<<SHT_HASH |
6111 | 0 | | 1u<<SHT_DYNAMIC |
6112 | 0 | | 1u<<SHT_NOTE |
6113 | 0 | | 1u<<SHT_REL |
6114 | 0 | | 1u<<SHT_RELA |
6115 | 0 | | 1u<<SHT_RELR |
6116 | 0 | | 1u<<SHT_DYNSYM // but not SHT_SYMTAB because compression confuses gdb |
6117 | 0 | | 1u<<SHT_STRTAB // .shstrtab and DYNSYM.sh_link; not SYMTAB.sh_link |
6118 | 0 | | 1u<<SHT_INIT_ARRAY |
6119 | 0 | | 1u<<SHT_FINI_ARRAY |
6120 | 0 | | 1u<<SHT_PREINIT_ARRAY |
6121 | 0 | | 1u<<(0x1f & SHT_GNU_versym) |
6122 | 0 | | 1u<<(0x1f & SHT_GNU_verneed) |
6123 | 0 | | 1u<<(0x1f & SHT_GNU_verdef) |
6124 | 0 | | 1u<<(0x1f & SHT_GNU_HASH); |
6125 | |
|
6126 | 0 | u32_t xct_off_hi = 0; |
6127 | 0 | Elf32_Phdr *ptr = phdri, *ptr_end = &phdri[e_phnum]; |
6128 | 0 | for (; ptr < ptr_end; ++ptr) { |
6129 | 0 | if (is_LOAD(ptr)) { |
6130 | 0 | u32_t hi = get_te32(&ptr->p_filesz) |
6131 | 0 | + get_te32(&ptr->p_offset); |
6132 | 0 | if (xct_off < hi) { |
6133 | 0 | xct_off_hi = hi; |
6134 | 0 | break; |
6135 | 0 | } |
6136 | 0 | } |
6137 | 0 | } |
6138 | |
|
6139 | 0 | MemBuffer mb_ask_for(e_shnum * sizeof(eho->e_shnum)); |
6140 | 0 | memset(mb_ask_for, 0, mb_ask_for.getSize()); |
6141 | 0 | unsigned short *const ask_for = (unsigned short *)mb_ask_for.getVoidPtr(); |
6142 | |
|
6143 | 0 | MemBuffer mb_shdro(e_shnum * sizeof(*shdri)); |
6144 | 0 | Elf32_Shdr *sh_out0 = (Elf32_Shdr *)mb_shdro.getVoidPtr(); |
6145 | 0 | Elf32_Shdr *sh_out = sh_out0; |
6146 | 0 | Elf32_Shdr *sh_in = shdri; |
6147 | 0 | Elf32_Shdr *n_shstrsec = nullptr; |
6148 | | |
6149 | | // Some binutils does tail merging on section names; we don't. |
6150 | | // ".plt" == (4+ ".rel.plt"); ".hash" == (4+ ".gnu.hash") |
6151 | 0 | MemBuffer mb_shstrings(100 + 2*get_te32(&sh_in[e_shstrndx].sh_size)); |
6152 | 0 | char *ptr_shstrings = (char *)&mb_shstrings[0]; |
6153 | 0 | *ptr_shstrings++ = '\0'; |
6154 | |
|
6155 | 0 | memset(sh_out, 0, sizeof(*sh_out)); // blank sh_out[0] |
6156 | 0 | ++sh_in; ++sh_out; unsigned n_sh_out = 1; |
6157 | |
|
6158 | 0 | for (unsigned j = 1; j < e_shnum; ++j, ++sh_in) { |
6159 | 0 | unsigned sh_name = get_te32(&sh_in->sh_name); |
6160 | 0 | unsigned sh_type = get_te32(&sh_in->sh_type); |
6161 | 0 | unsigned sh_flags = get_te32(&sh_in->sh_flags); |
6162 | | //unsigned sh_addr = get_te32(&sh_in->sh_addr); |
6163 | 0 | unsigned sh_offset = get_te32(&sh_in->sh_offset); |
6164 | 0 | unsigned sh_size = get_te32(&sh_in->sh_size); |
6165 | 0 | unsigned sh_info = get_te32(&sh_in->sh_info); |
6166 | 0 | char const *name = &shstrtab[sh_name]; |
6167 | 0 | if (ask_for[j]) { // Some previous _Shdr requested me |
6168 | | // Tell them my new index |
6169 | 0 | set_te32(&sh_out0[ask_for[j]].sh_info, n_sh_out); // sh_info vs st_shndx |
6170 | 0 | } |
6171 | 0 | if (sh_info < e_shnum) { // wild sh_info abounds! |
6172 | 0 | ask_for[sh_info] = j; // Enter my request, if any |
6173 | 0 | } |
6174 | 0 | if ( (sh_offset && sh_offset < xct_off) |
6175 | 0 | || (j == e_shstrndx) |
6176 | 0 | || (Elf32_Shdr::SHF_WRITE & sh_flags) |
6177 | 0 | || (sh_type < Elf32_Shdr::SHT_LOPROC |
6178 | 0 | && want_types_mask & (1<<(0x1f & sh_type))) |
6179 | 0 | || (Elf32_Shdr::SHT_ARM_ATTRIBUTES == sh_type) |
6180 | 0 | ) { |
6181 | 0 | *sh_out = *sh_in; // *sh_in is a candidate for fowarding |
6182 | 0 | if (sh_offset > xct_off) { // may slide down: earlier compression |
6183 | 0 | if (sh_offset >= xct_off_hi) { // easy: so_slide down |
6184 | 0 | if (Elf32_Shdr::SHT_ARM_ATTRIBUTES != sh_type) { |
6185 | 0 | slide_sh_offset(sh_out); |
6186 | 0 | } |
6187 | 0 | } |
6188 | 0 | else { // somewhere in compressed; try proportional (aligned) |
6189 | | // But note that PROGBITS without SHF_ALLOC |
6190 | | // will be dropped below. |
6191 | 0 | u32_t const slice = xct_off + (~0xFu & (unsigned)( |
6192 | 0 | (sh_offset - xct_off) * |
6193 | 0 | ((sh_offset - xct_off) / (float)(xct_off_hi - xct_off)))); |
6194 | | //set_te32(&sh_out->sh_addr, slice); |
6195 | 0 | set_te32(&sh_out->sh_offset, slice); |
6196 | 0 | } |
6197 | 0 | u32_t const max_sz = total_out - get_te32(&sh_out->sh_offset); |
6198 | 0 | if (sh_size > max_sz) { // avoid complaint "extends beyond EOF" |
6199 | 0 | set_te32(&sh_out->sh_size, max_sz); |
6200 | 0 | } |
6201 | 0 | } |
6202 | 0 | if (j == e_shstrndx) { // changes Elf32_Ehdr itself |
6203 | 0 | set_te16(&eho->e_shstrndx, sh_out - |
6204 | 0 | (Elf32_Shdr *)mb_shdro.getVoidPtr()); |
6205 | 0 | } |
6206 | 0 | if (Elf32_Shdr::SHT_ARM_ATTRIBUTES == sh_type |
6207 | 0 | || (SHT_NOTE == sh_type && xct_off < sh_offset) |
6208 | 0 | ) { // append a copy |
6209 | 0 | set_te32(&sh_out->sh_offset, total_out); |
6210 | 0 | fi->seek((upx_off_t)sh_offset, SEEK_SET); |
6211 | 0 | fi->read(ibuf, sh_size); |
6212 | 0 | fo->write(ibuf, sh_size); |
6213 | 0 | total_out += sh_size; |
6214 | 0 | } else |
6215 | 0 | if (SHT_PROGBITS == sh_type) { |
6216 | 0 | if (!(Elf32_Shdr::SHF_ALLOC & sh_flags)) { |
6217 | | // .debug_*, .gnu_debuglink etc. Typically compressed |
6218 | | // but not in RAM, and gdb (BFD) gets confused. |
6219 | 0 | continue; // OMIT the commit: do not forward |
6220 | 0 | } else |
6221 | 0 | if (sh_offset <= xct_off |
6222 | 0 | && 0 == strcmp(".text", name) ) { |
6223 | | // .text was compressed (but perhaps omitting some leading |
6224 | | // portion, if less than 4 PT_LOAD) |
6225 | 0 | set_te32(&sh_out->sh_size, so_slide + sh_size); |
6226 | | // FIXME: so_slide is negative; avoid negative result |
6227 | 0 | } |
6228 | 0 | } else |
6229 | 0 | if (SHT_STRTAB == sh_type) { |
6230 | 0 | if (j == e_shstrndx) { |
6231 | 0 | n_shstrsec = sh_out; |
6232 | 0 | } else |
6233 | 0 | if (strcmp(".dynstr", name)) { |
6234 | 0 | continue; // OMIT the commit of non-global symbol names |
6235 | 0 | } |
6236 | 0 | } |
6237 | 0 | set_te32(&sh_out->sh_name, ptr_shstrings - (char *)mb_shstrings.getVoidPtr()); |
6238 | 0 | do { // stupid MSVC lacks stpcpy() |
6239 | 0 | *ptr_shstrings++ = *name; |
6240 | 0 | } while (*name++); |
6241 | 0 | ++sh_out; ++n_sh_out; // actually commit the fowarding |
6242 | 0 | } |
6243 | 0 | } |
6244 | 0 | unsigned len = ptr_shstrings - (char *)mb_shstrings.getVoidPtr(); |
6245 | 0 | set_te32(&n_shstrsec->sh_offset, total_out); |
6246 | 0 | set_te32(&n_shstrsec->sh_size, len); |
6247 | 0 | fo->write(mb_shstrings, len); |
6248 | 0 | total_out += len; |
6249 | |
|
6250 | 0 | total_out = fpad4(fo, total_out); // align _Shdr[] |
6251 | 0 | set_te32(&eho->e_shoff, total_out); |
6252 | 0 | len = (char *)sh_out - (char *)mb_shdro.getVoidPtr(); |
6253 | 0 | set_te16(&eho->e_shnum, len / sizeof(*sh_out)); |
6254 | 0 | set_te16(&eho->e_shentsize, sizeof(Elf32_Shdr)); |
6255 | 0 | fo->write(mb_shdro, len); |
6256 | 0 | total_out += len; |
6257 | | |
6258 | | // Try to pacify gdb (before DT_INIT) by making it look like |
6259 | | // the compressed PT_LOAD extends all the way to the next PT_LOAD, |
6260 | | // with no gap in address space. Thus gdb should not complain about |
6261 | | // "Loadable section "..." [Shdr] outside of ELF segments [PT_LOAD]". |
6262 | | // gdb still "warning: section ... not found in .gnu_debugdata" |
6263 | | // because .gdb_debugdata is not present (or gets removed), |
6264 | | // but that is separate and "just" a warning. |
6265 | 0 | ptr = (Elf32_Phdr *)(1+ eho); |
6266 | 0 | if (0) // FIXME: This is not required? |
6267 | 0 | for (ptr_end = &ptr[e_phnum]; ptr < ptr_end; ++ptr) { |
6268 | 0 | if (is_LOAD(ptr)) { |
6269 | 0 | Elf32_Phdr *ptr2 = 1+ ptr; |
6270 | 0 | for (; ptr2 < ptr_end; ++ptr2) { |
6271 | 0 | if (is_LOAD(ptr2)) { |
6272 | 0 | unsigned pmask = 0u - get_te32(&ptr2->p_align); |
6273 | 0 | set_te32(&ptr->p_memsz, |
6274 | 0 | (pmask & get_te32(&ptr2->p_vaddr)) - |
6275 | 0 | (pmask & get_te32(&ptr ->p_vaddr)) ); |
6276 | 0 | ptr = ptr_end; // force end of outer loop |
6277 | 0 | ptr2 = ptr_end; // force end of inner loop |
6278 | 0 | } |
6279 | 0 | } |
6280 | 0 | } |
6281 | 0 | } |
6282 | |
|
6283 | 0 | fo->seek(0, SEEK_SET); |
6284 | 0 | fo->rewrite(eho, sizeof(*eho)); |
6285 | 0 | fo->seek(0, SEEK_END); |
6286 | 0 | } |
6287 | 0 | penalty = total_out - penalty; |
6288 | 0 | info("Android penalty = %d bytes", penalty); |
6289 | 0 | return penalty; |
6290 | 0 | } |
6291 | | |
6292 | | unsigned PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho) |
6293 | 0 | { |
6294 | 0 | if (!fo) { |
6295 | 0 | return 0; |
6296 | 0 | } |
6297 | 0 | unsigned penalty = total_out; |
6298 | 0 | if (Elf64_Ehdr::EM_AARCH64 == e_machine |
6299 | 0 | && saved_opt_android_shlib) { // Forward select _Shdr |
6300 | | // Keep _Shdr for rtld data (below xct_off). |
6301 | | // Discard _Shdr for compressed regions, except ".text" for gdb. |
6302 | | // Keep _Shdr with SHF_WRITE. |
6303 | | // Keep ARM_ATTRIBUTES |
6304 | | // Discard _Shdr with (0==sh_addr), except _Shdr[0] |
6305 | 0 | unsigned const want_types_mask = |
6306 | 0 | 1u<<SHT_SYMTAB |
6307 | 0 | | 1u<<SHT_RELA |
6308 | 0 | | 1u<<SHT_PROGBITS // see comment above |
6309 | 0 | | 1u<<SHT_HASH |
6310 | 0 | | 1u<<SHT_DYNAMIC |
6311 | 0 | | 1u<<SHT_NOTE |
6312 | 0 | | 1u<<SHT_REL |
6313 | 0 | | 1u<<SHT_RELR |
6314 | 0 | | 1u<<SHT_DYNSYM |
6315 | 0 | | 1u<<SHT_STRTAB // .shstrtab and .dynstr |
6316 | 0 | | 1u<<SHT_INIT_ARRAY |
6317 | 0 | | 1u<<SHT_FINI_ARRAY |
6318 | 0 | | 1u<<SHT_PREINIT_ARRAY |
6319 | 0 | | 1u<<(0x1f & SHT_GNU_versym) |
6320 | 0 | | 1u<<(0x1f & SHT_GNU_verneed) |
6321 | 0 | | 1u<<(0x1f & SHT_GNU_verdef) |
6322 | 0 | | 1u<<(0x1f & SHT_GNU_HASH); |
6323 | |
|
6324 | 0 | upx_uint64_t xct_off_hi = 0; |
6325 | 0 | Elf64_Phdr const *ptr = phdri, *ptr_end = &phdri[e_phnum]; |
6326 | 0 | for (; ptr < ptr_end; ++ptr) { |
6327 | 0 | if (is_LOAD(ptr)) { |
6328 | 0 | upx_uint64_t hi = get_te64(&ptr->p_filesz) |
6329 | 0 | + get_te64(&ptr->p_offset); |
6330 | 0 | if (xct_off < hi) { |
6331 | 0 | xct_off_hi = hi; |
6332 | 0 | break; |
6333 | 0 | } |
6334 | 0 | } |
6335 | 0 | } |
6336 | |
|
6337 | 0 | MemBuffer mb_ask_for(e_shnum * sizeof(eho->e_shnum)); |
6338 | 0 | memset(mb_ask_for, 0, mb_ask_for.getSize()); |
6339 | 0 | unsigned short *const ask_for = (unsigned short *)mb_ask_for.getVoidPtr(); |
6340 | |
|
6341 | 0 | MemBuffer mb_shdro(e_shnum * sizeof(*shdri)); |
6342 | 0 | Elf64_Shdr *sh_out0 = (Elf64_Shdr *)mb_shdro.getVoidPtr(); |
6343 | 0 | Elf64_Shdr *sh_out = sh_out0; |
6344 | 0 | Elf64_Shdr *sh_in = shdri; |
6345 | |
|
6346 | 0 | memset(sh_out, 0, sizeof(*sh_out)); // blank sh_out[0] |
6347 | 0 | ++sh_in; ++sh_out; unsigned n_sh_out = 1; |
6348 | |
|
6349 | 0 | for (unsigned j = 1; j < e_shnum; ++j, ++sh_in) { |
6350 | 0 | char const *sh_name = &shstrtab[get_te32(&sh_in->sh_name)]; |
6351 | 0 | (void)sh_name; // debugging |
6352 | 0 | unsigned sh_type = get_te32(&sh_in->sh_type); |
6353 | 0 | u64_t sh_flags = get_te64(&sh_in->sh_flags); |
6354 | 0 | u64_t sh_addr = get_te64(&sh_in->sh_addr); |
6355 | 0 | u64_t sh_offset = get_te64(&sh_in->sh_offset); |
6356 | 0 | u64_t sh_size = get_te64(&sh_in->sh_size); |
6357 | 0 | unsigned sh_info = get_te32(&sh_in->sh_info); |
6358 | 0 | if (ask_for[j]) { // Some previous _Shdr requested me |
6359 | | // Tell them my new index |
6360 | 0 | set_te32(&sh_out0[ask_for[j]].sh_info, n_sh_out); // sh_info vs st_shndx |
6361 | 0 | } |
6362 | 0 | if (sh_info < e_shnum) { // wild sh_info abounds! |
6363 | 0 | ask_for[sh_info] = j; // Enter my request, if any |
6364 | 0 | } |
6365 | 0 | if ( (sh_offset && sh_offset < xct_off) |
6366 | 0 | || (Elf64_Shdr::SHF_WRITE & sh_flags) |
6367 | 0 | || (j == e_shstrndx) |
6368 | 0 | || (sec_arm_attr == sh_in) |
6369 | 0 | || (want_types_mask & (1<<(0x1f & sh_type))) |
6370 | 0 | || (Elf32_Shdr::SHT_ARM_ATTRIBUTES == sh_type) |
6371 | 0 | ) { |
6372 | 0 | *sh_out = *sh_in; |
6373 | 0 | if (sh_offset > xct_off) { // may slide down: earlier compression |
6374 | 0 | if (sh_offset >= xct_off_hi) { // easy: so_slide down |
6375 | 0 | if (sh_out->sh_addr) // change only if non-zero |
6376 | 0 | set_te64(&sh_out->sh_addr, so_slide + sh_addr + |
6377 | 0 | (is_asl ? asl_delta : 0)); |
6378 | 0 | set_te64(&sh_out->sh_offset, so_slide + sh_offset); |
6379 | 0 | } |
6380 | 0 | else { // somewhere in compressed; try proportional (aligned) |
6381 | 0 | u64_t const slice = xct_off + (~0xFu & (unsigned)( |
6382 | 0 | (sh_offset - xct_off) * |
6383 | 0 | ((sh_offset - xct_off) / (float)(xct_off_hi - xct_off)))); |
6384 | 0 | set_te64(&sh_out->sh_addr, slice); |
6385 | 0 | set_te64(&sh_out->sh_offset, slice); |
6386 | 0 | } |
6387 | 0 | u64_t const max_sz = total_out - get_te64(&sh_out->sh_offset); |
6388 | 0 | if (sh_size > max_sz) { // avoid complaint "extends beyond EOF" |
6389 | 0 | set_te64(&sh_out->sh_size, max_sz); |
6390 | 0 | } |
6391 | 0 | } |
6392 | 0 | if (j == e_shstrndx) { // changes Elf64_Ehdr itself |
6393 | 0 | set_te16(&eho->e_shstrndx, sh_out - |
6394 | 0 | (Elf64_Shdr *)mb_shdro.getVoidPtr()); |
6395 | 0 | } |
6396 | 0 | if (j == e_shstrndx |
6397 | 0 | || sec_arm_attr == sh_in |
6398 | 0 | || (SHT_NOTE == sh_type && xct_off < sh_offset) |
6399 | 0 | ) { // append a copy |
6400 | 0 | set_te64(&sh_out->sh_offset, total_out); |
6401 | 0 | fi->seek((upx_off_t)sh_offset, SEEK_SET); |
6402 | 0 | fi->read(ibuf, sh_size); |
6403 | 0 | fo->write(ibuf, sh_size); |
6404 | 0 | total_out += sh_size; |
6405 | 0 | } else |
6406 | 0 | if (SHT_PROGBITS == sh_type) { |
6407 | 0 | if (sh_offset <= xct_off |
6408 | 0 | && 0 == strcmp(".text", shstrtab + get_te32(&sh_in->sh_name)) ) { |
6409 | | // .text was compressed (but perhaps omitting some leading |
6410 | | // portion, if less than 4 PT_LOAD) |
6411 | 0 | set_te64(&sh_out->sh_size, so_slide + sh_size); |
6412 | 0 | } else |
6413 | 0 | if (0 == sh_in->sh_addr) { // .gnu_debuglink etc |
6414 | 0 | set_te64(&sh_out->sh_offset, so_slide + sh_offset); |
6415 | 0 | } |
6416 | 0 | } |
6417 | | // Exploration for updating Shdrs from Dynamic, to pacify Android. |
6418 | | // Motivated by --force-pie with an input shared library; |
6419 | | // see https://github.com/upx/upx/issues/694 |
6420 | | // But then realized that the pointed-to regions typically were |
6421 | | // just above Elfhdrs (overlay_offset), so the data would be |
6422 | | // incorrect because occupied by compressed PT_LOADS. |
6423 | | // But don't lose the code, so comment-out via "if (0)". |
6424 | 0 | if (0) switch(sh_type) { // start {Shdr, Dynamic} pairs |
6425 | 0 | case SHT_DYNSYM: { |
6426 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_SYMTAB)); |
6427 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6428 | 0 | } break; |
6429 | 0 | case SHT_STRTAB: { |
6430 | 0 | if (e_shstrndx != j) { |
6431 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_STRTAB)); |
6432 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6433 | 0 | } |
6434 | 0 | } break; |
6435 | 0 | case SHT_GNU_versym: { |
6436 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_VERSYM)); |
6437 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6438 | 0 | } break; |
6439 | 0 | case SHT_GNU_verneed: { |
6440 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_VERNEED)); |
6441 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6442 | 0 | } break; |
6443 | 0 | case SHT_GNU_HASH: { |
6444 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_GNU_HASH)); |
6445 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6446 | 0 | } break; |
6447 | 0 | case SHT_HASH: { |
6448 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_HASH)); |
6449 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6450 | 0 | } break; |
6451 | 0 | case SHT_RELA: { |
6452 | 0 | if (0==strcmp(".rela.dyn", sh_name)) { |
6453 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_RELA)); |
6454 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6455 | 0 | } |
6456 | 0 | if (0==strcmp(".rela.plt", sh_name)) { |
6457 | 0 | set_te64(&sh_out->sh_addr, elf_unsigned_dynamic(Elf64_Dyn::DT_JMPREL)); |
6458 | 0 | sh_out->sh_offset = sh_out->sh_addr; |
6459 | 0 | } |
6460 | 0 | } break; |
6461 | 0 | } // end {Shdr, Dynamic} pairs |
6462 | 0 | ++sh_out; ++n_sh_out; |
6463 | 0 | } |
6464 | 0 | } |
6465 | 0 | total_out = fpad8(fo, total_out); |
6466 | 0 | set_te64(&eho->e_shoff, total_out); |
6467 | 0 | unsigned len = (char *)sh_out - (char *)mb_shdro.getVoidPtr(); |
6468 | 0 | set_te16(&eho->e_shnum, len / sizeof(*sh_out)); |
6469 | 0 | set_te16(&eho->e_shentsize, sizeof(Elf64_Shdr)); |
6470 | 0 | fo->write(mb_shdro, len); |
6471 | 0 | total_out += len; |
6472 | 0 | fo->seek(0, SEEK_SET); |
6473 | 0 | fo->rewrite(eho, sizeof(*eho)); |
6474 | 0 | fo->seek(0, SEEK_END); |
6475 | 0 | } |
6476 | 0 | penalty = total_out - penalty; |
6477 | 0 | info("Android penalty = %d bytes", penalty); |
6478 | 0 | return penalty; |
6479 | 0 | } |
6480 | | |
6481 | | void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft) |
6482 | 0 | { |
6483 | 0 | if (!xct_off) { |
6484 | 0 | overlay_offset = sz_elf_hdrs + sizeof(linfo); |
6485 | 0 | } |
6486 | |
|
6487 | 0 | cprElfHdr4 *eho = !xct_off |
6488 | 0 | ? (cprElfHdr4 *)(void *)&elfout // not shlib FIXME: ugly casting |
6489 | 0 | : (cprElfHdr4 *)lowmem.getVoidPtr(); // shlib |
6490 | 0 | unsigned penalty = forward_Shdrs(fo, &eho->ehdr); (void)penalty; |
6491 | |
|
6492 | 0 | if (opt->o_unix.preserve_build_id) { // FIXME: co-ordinate with forward_Shdrs |
6493 | | // calc e_shoff here and write shdrout, then o_shstrtab |
6494 | | //NOTE: these are pushed last to ensure nothing is stepped on |
6495 | | //for the UPX structure. |
6496 | 0 | total_out = fpad4(fo, total_out); |
6497 | 0 | set_te32(&eho->ehdr.e_shoff, total_out); |
6498 | |
|
6499 | 0 | unsigned const ssize = sizeof(shdrout); |
6500 | 0 | unsigned const ssize1 = get_te32(&shdrout.shdr[1].sh_size); |
6501 | 0 | unsigned const ssize2 = get_te32(&shdrout.shdr[2].sh_size); |
6502 | |
|
6503 | 0 | set_te32(&shdrout.shdr[2].sh_offset, ssize + total_out); |
6504 | 0 | set_te32(&shdrout.shdr[1].sh_offset, ssize2 + ssize + total_out); |
6505 | |
|
6506 | 0 | fo->write(&shdrout, ssize); total_out += ssize; |
6507 | |
|
6508 | 0 | fo->write(o_shstrtab, ssize2); total_out += ssize2; |
6509 | 0 | fo->write(buildid_data, ssize1); total_out += ssize1; |
6510 | 0 | } |
6511 | | |
6512 | | // ph.u_len and ph.c_len are leftover from earliest days when there was |
6513 | | // only one compressed extent. Use a good analogy for multiple extents. |
6514 | 0 | ph.u_len = file_size; |
6515 | 0 | ph.c_len = total_out; |
6516 | 0 | super::pack4(fo, ft); // write PackHeader and overlay_offset |
6517 | |
|
6518 | 0 | fo->seek(0, SEEK_SET); |
6519 | 0 | if (0!=xct_off) { // shared library |
6520 | 0 | { // Shouldn't this special case be handled earlier? |
6521 | 0 | if (overlay_offset < xct_off) { |
6522 | 0 | Elf32_Phdr *phdro = (Elf32_Phdr *)&eho->phdr; |
6523 | 0 | set_te32(&phdro->p_flags, Elf32_Phdr::PF_X | get_te32(&phdro->p_flags)); |
6524 | 0 | } |
6525 | 0 | } |
6526 | 0 | if (!sec_arm_attr && !saved_opt_android_shlib) { |
6527 | | // Make it abundantly clear that there are no Elf32_Shdr in this shlib |
6528 | 0 | eho->ehdr.e_shoff = 0; |
6529 | 0 | set_te16(&eho->ehdr.e_shentsize, sizeof(Elf32_Shdr)); // Android bug: cannot use 0 |
6530 | 0 | eho->ehdr.e_shnum = 0; |
6531 | 0 | eho->ehdr.e_shstrndx = 0; |
6532 | 0 | } |
6533 | 0 | fo->rewrite(eho, sizeof(ehdri) + e_phnum * sizeof(*phdri)); |
6534 | 0 | fo->seek(linfo_off, SEEK_SET); |
6535 | 0 | fo->rewrite(&linfo, sizeof(linfo)); // new info: l_checksum, l_size |
6536 | |
|
6537 | 0 | if (jni_onload_va) { |
6538 | 0 | unsigned tmp = sz_pack2 + get_te32(&eho->phdr[C_TEXT].p_vaddr); |
6539 | 0 | tmp |= (Elf32_Ehdr::EM_ARM==e_machine); // THUMB mode |
6540 | 0 | set_te32(&tmp, tmp); |
6541 | 0 | fo->seek(ptr_udiff_bytes(&jni_onload_sym->st_value, file_image), SEEK_SET); |
6542 | 0 | fo->rewrite(&tmp, sizeof(tmp)); |
6543 | 0 | } |
6544 | 0 | } |
6545 | 0 | else { // not shlib |
6546 | | // Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel |
6547 | | // tries to make .bss, which requires PF_W. |
6548 | | // But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X. |
6549 | 0 | set_te32(&eho->phdr[C_TEXT].p_filesz, sz_pack2 + lsize); |
6550 | 0 | eho->phdr[C_TEXT].p_memsz = eho->phdr[C_TEXT].p_filesz; |
6551 | |
|
6552 | 0 | fo->seek(0, SEEK_SET); |
6553 | 0 | fo->rewrite(&eho->ehdr, sizeof(Elf32_Ehdr) + 2* sizeof(Elf32_Phdr)); // C_BASE, C_TEXT |
6554 | 0 | fo->seek(overlay_offset - sizeof(l_info), SEEK_SET); |
6555 | 0 | fo->rewrite(&linfo, sizeof(linfo)); |
6556 | 0 | } |
6557 | 0 | } |
6558 | | |
6559 | | void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft) |
6560 | 0 | { |
6561 | 0 | if (!xct_off) { |
6562 | 0 | overlay_offset = sz_elf_hdrs + sizeof(linfo); |
6563 | 0 | } |
6564 | |
|
6565 | 0 | cprElfHdr4 *eho = !xct_off |
6566 | 0 | ? &elfout // not shlib |
6567 | 0 | : (cprElfHdr4 *)lowmem.getVoidPtr(); // shlib |
6568 | 0 | unsigned penalty = forward_Shdrs(fo, &eho->ehdr); (void)penalty; |
6569 | |
|
6570 | 0 | if (opt->o_unix.preserve_build_id) { // FIXME: co-ordinate with forward_Shdrs |
6571 | | // calc e_shoff here and write shdrout, then o_shstrtab |
6572 | | //NOTE: these are pushed last to ensure nothing is stepped on |
6573 | | //for the UPX structure. |
6574 | 0 | total_out = fpad4(fo, total_out); |
6575 | 0 | set_te64(&eho->ehdr.e_shoff, total_out); |
6576 | |
|
6577 | 0 | unsigned const ssize = sizeof(shdrout); |
6578 | 0 | unsigned const ssize1 = get_te64(&shdrout.shdr[1].sh_size); |
6579 | 0 | unsigned const ssize2 = get_te64(&shdrout.shdr[2].sh_size); |
6580 | |
|
6581 | 0 | set_te64(&shdrout.shdr[2].sh_offset, ssize + total_out); |
6582 | 0 | set_te64(&shdrout.shdr[1].sh_offset, ssize2 + ssize + total_out); |
6583 | |
|
6584 | 0 | fo->write(&shdrout, ssize); total_out += ssize; |
6585 | |
|
6586 | 0 | fo->write(o_shstrtab, ssize2); total_out += ssize2; |
6587 | 0 | fo->write(buildid_data, ssize1); total_out += ssize1; |
6588 | 0 | } |
6589 | | |
6590 | | // ph.u_len and ph.c_len are leftover from earliest days when there was |
6591 | | // only one compressed extent. Use a good analogy for multiple extents. |
6592 | 0 | ph.u_len = file_size; |
6593 | 0 | ph.c_len = total_out; |
6594 | 0 | super::pack4(fo, ft); // write PackHeader and overlay_offset |
6595 | |
|
6596 | 0 | fo->seek(0, SEEK_SET); |
6597 | 0 | if (0!=xct_off) { // shared library |
6598 | 0 | { // Shouldn't this special case be handled earlier? |
6599 | 0 | if (overlay_offset < xct_off) { |
6600 | 0 | Elf64_Phdr *phdro = (Elf64_Phdr *)(&eho->phdr); |
6601 | 0 | set_te32(&phdro->p_flags, Elf64_Phdr::PF_X | get_te32(&phdro->p_flags)); |
6602 | 0 | } |
6603 | 0 | } |
6604 | 0 | if (!sec_arm_attr && !saved_opt_android_shlib) { |
6605 | | // Make it abundantly clear that there are no Elf64_Shdr in this shlib |
6606 | 0 | eho->ehdr.e_shoff = 0; |
6607 | 0 | set_te16(&eho->ehdr.e_shentsize, sizeof(Elf64_Shdr)); // Android bug: cannot use 0 |
6608 | 0 | eho->ehdr.e_shnum = 0; |
6609 | 0 | eho->ehdr.e_shstrndx = 0; |
6610 | 0 | } |
6611 | |
|
6612 | 0 | fo->rewrite(eho, sizeof(ehdri) + e_phnum * sizeof(*phdri)); |
6613 | 0 | fo->seek(linfo_off, SEEK_SET); |
6614 | 0 | fo->rewrite(&linfo, sizeof(linfo)); // new info: l_checksum, l_size |
6615 | |
|
6616 | 0 | if (jni_onload_va) { // FIXME Does this apply to 64-bit, too? |
6617 | 0 | upx_uint64_t tmp = sz_pack2 + get_te64(&eho->phdr[C_TEXT].p_vaddr); |
6618 | 0 | tmp |= (Elf64_Ehdr::EM_ARM==e_machine); // THUMB mode; no-op for 64-bit |
6619 | 0 | set_te64(&tmp, tmp); |
6620 | 0 | fo->seek(ptr_udiff_bytes(&jni_onload_sym->st_value, file_image), SEEK_SET); |
6621 | 0 | fo->rewrite(&tmp, sizeof(tmp)); |
6622 | 0 | } |
6623 | 0 | } |
6624 | 0 | else { // not shlib |
6625 | | // Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel |
6626 | | // tries to make .bss, which requires PF_W. |
6627 | | // But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X. |
6628 | 0 | set_te64(&eho->phdr[C_TEXT].p_filesz, sz_pack2 + lsize); |
6629 | 0 | eho->phdr[C_TEXT].p_memsz = eho->phdr[C_TEXT].p_filesz; |
6630 | |
|
6631 | 0 | fo->seek(0, SEEK_SET); |
6632 | 0 | fo->rewrite(&eho->ehdr, sizeof(Elf64_Ehdr) + 2* sizeof(Elf64_Phdr)); // C_BASE, C_TEXT |
6633 | 0 | fo->seek(overlay_offset - sizeof(l_info), SEEK_SET); |
6634 | 0 | fo->rewrite(&linfo, sizeof(linfo)); |
6635 | 0 | } |
6636 | 0 | } |
6637 | | |
6638 | | void |
6639 | | PackLinuxElf32::unRel32( |
6640 | | unsigned dt_rel, |
6641 | | Elf32_Rel *rel0, |
6642 | | unsigned relsz, |
6643 | | MemBuffer &ptload1, |
6644 | | unsigned const load_off, |
6645 | | OutputFile *fo |
6646 | | ) |
6647 | 0 | { |
6648 | 0 | Elf32_Rel *rel = rel0; |
6649 | 0 | for (int k = relsz / sizeof(Elf32_Rel); --k >= 0; ++rel) { |
6650 | 0 | unsigned r_offset = get_te32(&rel->r_offset); |
6651 | 0 | unsigned r_info = get_te32(&rel->r_info); |
6652 | 0 | unsigned r_type = ELF32_R_TYPE(r_info); |
6653 | 0 | if (xct_off <= r_offset) { |
6654 | 0 | set_te32(&rel->r_offset, r_offset - asl_delta); |
6655 | 0 | } |
6656 | 0 | if (Elf32_Ehdr::EM_ARM == e_machine) { |
6657 | 0 | if (R_ARM_RELATIVE == r_type) { |
6658 | 0 | unsigned d = r_offset - load_off - asl_delta; |
6659 | 0 | unsigned w = get_te32(&ptload1[d]); |
6660 | 0 | if (xct_off <= w) { |
6661 | 0 | set_te32(&ptload1[d], w - asl_delta); |
6662 | 0 | } |
6663 | 0 | } |
6664 | 0 | if (R_ARM_JUMP_SLOT == r_type) { |
6665 | 0 | ++n_jmp_slot; |
6666 | | // .rel.plt contains offset of the "first time" target |
6667 | 0 | unsigned d = r_offset - load_off - asl_delta; |
6668 | 0 | if (plt_va > d) { |
6669 | 0 | plt_va = d; |
6670 | 0 | } |
6671 | 0 | unsigned w = get_te32(&ptload1[d]); |
6672 | 0 | if (xct_off <= w) { |
6673 | 0 | set_te32(&ptload1[d], w - asl_delta); |
6674 | 0 | } |
6675 | 0 | } |
6676 | 0 | } |
6677 | 0 | if (Elf32_Ehdr::EM_386 == e_machine) { |
6678 | 0 | if (R_386_RELATIVE == r_type) { |
6679 | 0 | unsigned d = r_offset - load_off - asl_delta; |
6680 | 0 | unsigned w = get_te32(&ptload1[d]); |
6681 | 0 | if (xct_off <= w) { |
6682 | 0 | set_te32(&ptload1[d], w - asl_delta); |
6683 | 0 | } |
6684 | 0 | } |
6685 | 0 | if (R_386_JMP_SLOT == r_type) { |
6686 | 0 | ++n_jmp_slot; |
6687 | | // .rel.plt contains offset of the "first time" target |
6688 | 0 | unsigned d = r_offset - load_off - asl_delta; |
6689 | 0 | if (plt_va > d) { |
6690 | 0 | plt_va = d; |
6691 | 0 | } |
6692 | 0 | unsigned w = get_te32(&ptload1[d]); |
6693 | 0 | if (xct_off <= w) { |
6694 | 0 | set_te32(&ptload1[d], w - asl_delta); |
6695 | 0 | } |
6696 | 0 | } |
6697 | 0 | } |
6698 | 0 | } |
6699 | 0 | fo->seek(dt_rel, SEEK_SET); |
6700 | 0 | fo->rewrite(rel0, relsz); |
6701 | 0 | } |
6702 | | |
6703 | | void |
6704 | | PackLinuxElf64::unRela64( |
6705 | | upx_uint64_t const dt_rela, |
6706 | | Elf64_Rela *const rela0, |
6707 | | unsigned const relasz, |
6708 | | upx_uint64_t const old_dtinit, |
6709 | | OutputFile *const fo |
6710 | | ) |
6711 | 0 | { |
6712 | 0 | Elf64_Rela *rela = rela0; |
6713 | 0 | for (int k = relasz / sizeof(Elf64_Rela); --k >= 0; ++rela) { |
6714 | 0 | upx_uint64_t r_addend = get_te64(&rela->r_addend); |
6715 | 0 | if (xct_off <= r_addend) { |
6716 | 0 | r_addend -= asl_delta; |
6717 | 0 | set_te64(&rela->r_addend, r_addend); |
6718 | 0 | } |
6719 | |
|
6720 | 0 | upx_uint64_t r_offset = get_te64(&rela->r_offset); |
6721 | 0 | if (xct_off <= r_offset) { |
6722 | | //r_offset -= asl_delta; // keep compressed value vs plt_va |
6723 | 0 | set_te64(&rela->r_offset, r_offset - asl_delta); // uncompressed value |
6724 | 0 | } |
6725 | | |
6726 | | // ElfXX_Rela (used only on 64-bit) ignores the contents of memory |
6727 | | // at the target designated by r_offset. The target is completely |
6728 | | // overwritten by (r_addend + f_reloc(r_info)). |
6729 | | // |
6730 | | // Nevertheless, the existing targets of .rela.plt in the .got |
6731 | | // seem to have values that matter to somebody. So restore original |
6732 | | // values when is_asl. |
6733 | 0 | upx_uint64_t r_info = get_te64(&rela->r_info); |
6734 | 0 | unsigned r_type = ELF64_R_TYPE(r_info); |
6735 | 0 | if (is_asl && Elf64_Ehdr::EM_AARCH64 == e_machine) { |
6736 | 0 | if (R_AARCH64_RELATIVE == r_type) { |
6737 | | #if 0 //{ FIXME |
6738 | | if (old_dtinit == r_addend) { |
6739 | | set_te64(&ptload1[r_offset - plt_va], r_addend); |
6740 | | } |
6741 | | #endif //} |
6742 | 0 | } |
6743 | 0 | if (R_AARCH64_JUMP_SLOT == r_type) { |
6744 | 0 | ++n_jmp_slot; |
6745 | | // .rela.plt contains offset of the "first time" target |
6746 | 0 | if (jump_slots.getSize() < (r_offset - plt_va)) { |
6747 | 0 | throwInternalError("bad r_offset for jump_slots"); |
6748 | 0 | } |
6749 | | // really upx_uint64_t *, but clang makes it hard to say that |
6750 | 0 | unsigned char *slot = r_offset - plt_va |
6751 | 0 | + (unsigned char *)jump_slots.getVoidPtr(); |
6752 | 0 | upx_uint64_t w = get_te64(slot); |
6753 | 0 | if (xct_off <= w) { |
6754 | 0 | set_te64(slot, w - asl_delta); |
6755 | 0 | } |
6756 | 0 | } |
6757 | 0 | } |
6758 | | // FIXME: but what about old_dtinit? |
6759 | 0 | (void)old_dtinit; |
6760 | |
|
6761 | 0 | } // end each RELA |
6762 | 0 | if (fo) { |
6763 | 0 | fo->seek(dt_rela, SEEK_SET); |
6764 | 0 | fo->rewrite(rela0, relasz); |
6765 | 0 | } |
6766 | 0 | } |
6767 | | |
6768 | | void |
6769 | | PackLinuxElf64::un_asl_dynsym( // ibuf has the input |
6770 | | unsigned orig_file_size, |
6771 | | OutputFile *fo // else just leave in ibuf |
6772 | | ) |
6773 | 0 | { |
6774 | | // un-Relocate dynsym (DT_SYMTAB) which is below xct_off |
6775 | 0 | dynstr = (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB); |
6776 | 0 | sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM); |
6777 | 0 | if (dynstr && sec_dynsym) { |
6778 | 0 | upx_uint64_t const off_dynsym = get_te64(&sec_dynsym->sh_offset); |
6779 | 0 | upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size); |
6780 | 0 | if (orig_file_size < sz_dynsym |
6781 | 0 | || orig_file_size < off_dynsym |
6782 | 0 | || (orig_file_size - off_dynsym) < sz_dynsym) { |
6783 | 0 | throwCantUnpack("bad SHT_DYNSYM"); |
6784 | 0 | } |
6785 | 0 | Elf64_Sym *const sym0 = (Elf64_Sym *)ibuf.subref( |
6786 | 0 | "bad dynsym", off_dynsym, sz_dynsym); |
6787 | 0 | Elf64_Sym *sym = sym0; |
6788 | 0 | for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) { |
6789 | 0 | upx_uint64_t symval = get_te64(&sym->st_value); |
6790 | 0 | unsigned symsec = get_te16(&sym->st_shndx); |
6791 | 0 | if (Elf64_Sym::SHN_UNDEF != symsec |
6792 | 0 | && Elf64_Sym::SHN_ABS != symsec |
6793 | 0 | && xct_off <= symval) { |
6794 | 0 | set_te64(&sym->st_value, symval - asl_delta); |
6795 | 0 | } |
6796 | 0 | if (Elf64_Sym::SHN_ABS == symsec && xct_off <= symval) { |
6797 | 0 | adjABS(sym, 0ul - (unsigned long)asl_delta); |
6798 | 0 | } |
6799 | 0 | } |
6800 | 0 | if (fo) { |
6801 | 0 | unsigned pos = fo->tell(); |
6802 | 0 | fo->seek(off_dynsym, SEEK_SET); |
6803 | 0 | fo->rewrite(sym0, sz_dynsym); |
6804 | 0 | fo->seek(pos, SEEK_SET); |
6805 | 0 | } |
6806 | 0 | } |
6807 | 0 | } |
6808 | | |
6809 | | void |
6810 | | PackLinuxElf32::un_asl_dynsym( // ibuf has the input |
6811 | | unsigned orig_file_size, |
6812 | | OutputFile *fo // else just leave in ibuf |
6813 | | ) |
6814 | 0 | { |
6815 | | // un-Relocate dynsym (DT_SYMTAB) which is below xct_off |
6816 | 0 | dynstr = (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB); |
6817 | 0 | sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM); |
6818 | 0 | if (dynstr && sec_dynsym) { |
6819 | 0 | upx_uint32_t const off_dynsym = get_te32(&sec_dynsym->sh_offset); |
6820 | 0 | upx_uint32_t const sz_dynsym = get_te32(&sec_dynsym->sh_size); |
6821 | 0 | if (orig_file_size < sz_dynsym |
6822 | 0 | || orig_file_size < off_dynsym |
6823 | 0 | || (orig_file_size - off_dynsym) < sz_dynsym) { |
6824 | 0 | throwCantUnpack("bad SHT_DYNSYM"); |
6825 | 0 | } |
6826 | 0 | Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref( |
6827 | 0 | "bad dynsym", off_dynsym, sz_dynsym); |
6828 | 0 | Elf32_Sym *sym = sym0; |
6829 | 0 | for (int j = sz_dynsym / sizeof(Elf32_Sym); --j>=0; ++sym) { |
6830 | 0 | upx_uint32_t symval = get_te32(&sym->st_value); |
6831 | 0 | unsigned symsec = get_te16(&sym->st_shndx); |
6832 | 0 | if (Elf32_Sym::SHN_UNDEF != symsec |
6833 | 0 | && Elf32_Sym::SHN_ABS != symsec |
6834 | 0 | && xct_off <= symval) { |
6835 | 0 | set_te32(&sym->st_value, symval - asl_delta); |
6836 | 0 | } |
6837 | 0 | if (Elf32_Sym::SHN_ABS == symsec && xct_off <= symval) { |
6838 | 0 | adjABS(sym, 0u - (unsigned)asl_delta); |
6839 | 0 | } |
6840 | 0 | } |
6841 | 0 | if (fo) { |
6842 | 0 | unsigned pos = fo->tell(); |
6843 | 0 | fo->seek(off_dynsym, SEEK_SET); |
6844 | 0 | fo->rewrite(sym0, sz_dynsym); |
6845 | 0 | fo->seek(pos, SEEK_SET); |
6846 | 0 | } |
6847 | 0 | } |
6848 | 0 | } |
6849 | | |
6850 | | // File layout of compressed .so (new-style: 3 or 4 PT_LOAD) shared library: |
6851 | | // 1. new Elf headers: Ehdr, PT_LOAD (r-x), PT_LOAD (rw-, if any), non-PT_LOAD Phdrs |
6852 | | // 2. Space for (original - 2) PT_LOAD Phdr |
6853 | | // 3. Remaining original contents of file below xct_off |
6854 | | // xct_off: (&lowest eXecutable Shdr section; in original PT_LOAD[0] or [1]) |
6855 | | // 3a. If --android-shlib, then 4KiB page of Shdr copy, etc. (asl_pack2_Shdrs) |
6856 | | // And xct_off gets incremented by 4KiB at the right time. |
6857 | | // 4. l_info (12 bytes) |
6858 | | // overlay_offset: |
6859 | | // 5. p_info (12 bytes) |
6860 | | // 6. compressed original Elf headers (prefixed by b_info as usual) |
6861 | | // 6a. un-compressed copy of input after Elf headers until xct_off. |
6862 | | // *user_init_rp has been modified if no DT_INIT |
6863 | | // 7. compressed remainder of PT_LOAD above xct_off |
6864 | | // 8. compressed read-only PT_LOAD above xct_off (if any) // FIXME: check decompressor |
6865 | | // 9. uncompressed Read-Write PT_LOAD (slide down N pages) |
6866 | | // 10. int[6] tables for UPX runtime de-compressor |
6867 | | // (new) DT_INIT: |
6868 | | // 11. UPX runtime de-compressing loader |
6869 | | // 12. compressed gaps between PT_LOADs (and EOF) above xct_off |
6870 | | // 13. 32-byte pack header |
6871 | | // 14. 4-byte overlay_offset |
6872 | | |
6873 | | void PackLinuxElf64::un_shlib_1( |
6874 | | OutputFile *const fo, |
6875 | | MemBuffer &o_elfhdrs, |
6876 | | unsigned &c_adler, |
6877 | | unsigned &u_adler, |
6878 | | unsigned const orig_file_size |
6879 | | ) |
6880 | 185 | { |
6881 | | // xct_off [input side] was set by ::unpack when is_shlib |
6882 | | // yct_off [output side] set here unless is_asl in next 'if' block |
6883 | 185 | unsigned yct_off = xct_off; |
6884 | | |
6885 | | // Below xct_off is not compressed (for benefit of rtld.) |
6886 | 185 | fi->seek(0, SEEK_SET); |
6887 | 185 | fi->readx(ibuf, umin(blocksize, file_size_u32)); |
6888 | | |
6889 | | // Determine if the extra page with copy of _Shdrs was spliced in. |
6890 | | // This used to be the result of --android-shlib. |
6891 | | // But in 2023-02 the forwarding of ARM_ATTRIBUTES (by appending) |
6892 | | // takes care of this, so the 5th word before e_entry does not |
6893 | | // have the low bit 1, so is_asl should not be set. |
6894 | | // However, .so that were compressed before 2023-03 |
6895 | | // may be marked. |
6896 | 185 | e_shoff = get_te64(&ehdri.e_shoff); |
6897 | 185 | if (e_shoff && e_shnum |
6898 | | // +36: (sizeof(PackHeader) + sizeof(overlay_offset)) |
6899 | | // after Shdrs for ARM_ATTRIBUTES |
6900 | 104 | && (((e_shoff + sizeof(Elf64_Shdr) * e_shnum) + 36) < file_size_u) |
6901 | 185 | ) { // possible --android-shlib |
6902 | 10 | unsigned x = get_te32(&file_image[get_te64(&ehdri.e_entry) - (1+ 4)*sizeof(int)]); |
6903 | 10 | if (1 & x) { // the clincher |
6904 | 1 | is_asl = 1; |
6905 | 1 | fi->seek(e_shoff, SEEK_SET); |
6906 | 1 | mb_shdr.alloc( sizeof(Elf64_Shdr) * e_shnum); |
6907 | 1 | shdri = (Elf64_Shdr *)mb_shdr.getVoidPtr(); |
6908 | 1 | fi->readx(shdri, sizeof(Elf64_Shdr) * e_shnum); |
6909 | 1 | yct_off = get_te64(&shdri->sh_offset); // for the output file (de-compressed) |
6910 | 1 | xct_off = asl_delta + yct_off; // for the input file (compressed) |
6911 | 1 | } |
6912 | 10 | } |
6913 | | |
6914 | | // Decompress first Extent. Old style covers [0, xct_off) |
6915 | | // which includes rtld constant data and eXecutable app code below DT_INIT. |
6916 | | // In old style, the first compressed Extent is redundant |
6917 | | // except for the compressed original Elf headers. |
6918 | | // New style covers just Elf headers: the rest below xct_off is |
6919 | | // rtld constant data: DT_*HASH, DT_SYMTAB, DT_STRTAB, etc. |
6920 | | // New style puts eXecutable app code in second PT_LOAD |
6921 | | // in order to mark Elf headers and rtld data as non-eXecutable. |
6922 | 185 | fi->seek(overlay_offset - sizeof(l_info), SEEK_SET); |
6923 | 185 | struct { |
6924 | 185 | struct l_info l; |
6925 | 185 | struct p_info p; |
6926 | 185 | struct b_info b; |
6927 | 185 | } hdr; |
6928 | 185 | fi->readx(&hdr, sizeof(hdr)); |
6929 | 185 | if (hdr.l.l_magic != UPX_MAGIC_LE32 |
6930 | 176 | || get_te16(&hdr.l.l_lsize) != (unsigned)lsize |
6931 | 176 | || get_te32(&hdr.p.p_filesize) != ph.u_file_size |
6932 | 135 | || get_te32(&hdr.b.sz_unc) < sz_elf_hdrs // peek: 1st b_info covers Elf headers |
6933 | 185 | ) { |
6934 | 49 | throwCantUnpack("corrupt l_info/p_info/b_info"); |
6935 | 49 | } |
6936 | 136 | fi->seek(-(off_t)sizeof(struct b_info), SEEK_CUR); // hdr.b_info was a peek |
6937 | | |
6938 | | // The default layout for a shared library created by binutils-2.29 |
6939 | | // (Fedora 28; 2018) has two PT_LOAD: permissions r-x and rw-. |
6940 | | // xct_off (the lowest address of executable instructions; |
6941 | | // the highest address of read-only data used by rtld (ld-linux)) |
6942 | | // will be somewhere in the first PT_LOAD. |
6943 | | // |
6944 | | // The default layout for a shared library created by binutils-2.31 |
6945 | | // (Fedora 29; 2018) has four PT_LOAD: permissions r--, r-x, r--, rw-. |
6946 | | // xct_off will be the base of the second [r-x] PT_LOAD. |
6947 | | // |
6948 | | // Bytes below xct_off cannot be compressed because they are used |
6949 | | // by rtld *before* the UPX run-time de-compression stub gets control |
6950 | | // via DT_INIT. Bytes in a Writeable PT_LOAD cannot be compressed |
6951 | | // because they may be relocated by rtld, again before stub execution. |
6952 | | // |
6953 | | // We need to know which layout of PT_LOAD. It seems risky to steal |
6954 | | // bits in the input ElfXX_Ehdr or ElfXX_Phdr, so we decompress |
6955 | | // the first compressed block. For an old-style shared library |
6956 | | // the first compressed block covers [0, xct_off) which is redundant |
6957 | | // with the interval [sz_elf_hdrs, xct_off) because those bytes |
6958 | | // must be present for use by rtl (So that is a large inefficiency.) |
6959 | | // Fortunately p_info.p_blocksize fits in ibuf, and unpackExtent |
6960 | | // will just decompress it all. For new style, the first compressed |
6961 | | // block covers [0, sz_elf_hdrs). |
6962 | | |
6963 | | // Peek: unpack into ibuf, but do not write |
6964 | 136 | unsigned const sz_block1 = unpackExtent(sz_elf_hdrs, nullptr, |
6965 | 136 | c_adler, u_adler, false, -1); |
6966 | 136 | if (sz_block1 < sz_elf_hdrs) { |
6967 | 0 | throwCantUnpack("corrupt b_info"); |
6968 | 0 | } |
6969 | 136 | memcpy(o_elfhdrs, ibuf, sz_elf_hdrs); // save de-compressed Elf headers |
6970 | 136 | Elf64_Ehdr const *const ehdro = (Elf64_Ehdr const *)(void const *)o_elfhdrs; |
6971 | 136 | if (ehdro->e_type !=ehdri.e_type |
6972 | 105 | || ehdro->e_machine!=ehdri.e_machine |
6973 | 105 | || ehdro->e_version!=ehdri.e_version |
6974 | | // less strict for EM_PPC64 to workaround earlier bug |
6975 | 105 | || !( ehdro->e_flags==ehdri.e_flags |
6976 | 16 | || Elf64_Ehdr::EM_PPC64 == get_te16(&ehdri.e_machine)) |
6977 | 92 | || ehdro->e_ehsize !=ehdri.e_ehsize |
6978 | | // check EI_MAG[0-3], EI_CLASS, EI_DATA, EI_VERSION |
6979 | 87 | || memcmp(ehdro->e_ident, ehdri.e_ident, Elf64_Ehdr::EI_OSABI)) { |
6980 | 23 | throwCantUnpack("ElfXX_Ehdr corrupted"); |
6981 | 23 | } |
6982 | 113 | if (fo) { |
6983 | 53 | fo->write(ibuf, sz_block1); |
6984 | 53 | total_out = sz_block1; |
6985 | 53 | } |
6986 | 113 | Elf64_Phdr const *o_phdr = (Elf64_Phdr const *)(1+ ehdro); |
6987 | | // Handle compressed PT_LOADs (must not have PF_W) |
6988 | 113 | unsigned not_first_LOAD = 0; |
6989 | 289 | for (unsigned j = 0; j < e_phnum; ++j, ++o_phdr) { |
6990 | 176 | unsigned type = get_te32(&o_phdr->p_type); |
6991 | 176 | unsigned flags = get_te32(&o_phdr->p_flags); |
6992 | 176 | if (PT_LOAD != type || Elf64_Phdr::PF_W & flags) { |
6993 | 150 | continue; |
6994 | 150 | } |
6995 | 26 | unsigned p_offset = get_te64(&o_phdr->p_offset); |
6996 | 26 | unsigned p_filesz = get_te64(&o_phdr->p_filesz); |
6997 | 26 | unsigned wanted = p_filesz; |
6998 | 26 | if (!not_first_LOAD++) { // first PT_LOAD |
6999 | 25 | wanted -= sz_block1; |
7000 | 25 | if (sz_block1 > sz_elf_hdrs) { // old style |
7001 | 24 | if (is_asl) { |
7002 | 0 | un_asl_dynsym(orig_file_size, fo); |
7003 | 0 | } |
7004 | 24 | p_offset += sz_block1; |
7005 | 24 | } |
7006 | 25 | if (sz_block1 == sz_elf_hdrs) { // new style |
7007 | 1 | unsigned const len = (yct_off ? yct_off : xct_off) - sz_elf_hdrs; |
7008 | 1 | unsigned const ipos = fi->tell(); |
7009 | 1 | fi->seek(sz_elf_hdrs, SEEK_SET); |
7010 | 1 | fi->readx(&ibuf[sz_elf_hdrs], len); |
7011 | 1 | if (is_asl) { |
7012 | 0 | un_asl_dynsym(orig_file_size, nullptr); |
7013 | 0 | } |
7014 | 1 | if (fo) { |
7015 | 0 | fo->write(&ibuf[sz_elf_hdrs], len); |
7016 | 0 | } |
7017 | 1 | total_out += len; |
7018 | | |
7019 | | // github-issue629: (overlay_offset = 0xa500), so initially (xct_off = 0xa494). |
7020 | | // But "yct_off = get_te64(&shdri->sh_offset)" so if _Shdrs are aligned (??) |
7021 | | // then (0x10500 == (xct_off = asl_delta + yct_off)), and we read+write |
7022 | | // more than we need. |
7023 | | // So assume the excess just lives there, or is overwritten later by seek+write. |
7024 | 1 | if (wanted < len) { // FIXME: why does this happen? |
7025 | 0 | wanted = 0; |
7026 | 0 | } |
7027 | 1 | else { |
7028 | 1 | wanted -= len; |
7029 | 1 | } |
7030 | 1 | fi->seek(ipos, SEEK_SET); |
7031 | 1 | if (total_out == p_filesz) { |
7032 | 0 | continue; // already entirely re-generated |
7033 | 0 | } |
7034 | 1 | p_offset = total_out; |
7035 | 1 | } |
7036 | 25 | } |
7037 | 26 | if (fo) { |
7038 | 10 | fo->seek(p_offset, SEEK_SET); |
7039 | 10 | } |
7040 | 26 | unpackExtent(wanted, fo, c_adler, u_adler, false); |
7041 | 26 | } |
7042 | 113 | funpad4(fi); |
7043 | 113 | loader_offset = fi->tell(); |
7044 | | |
7045 | | // Handle PT_LOAD with PF_W: writeable, so not compressed. "Slide" |
7046 | 113 | o_phdr = (Elf64_Phdr const *)(1+ ehdro); |
7047 | 113 | Elf64_Phdr const *i_phdr = phdri; |
7048 | 272 | for (unsigned j = 0; j < e_phnum; ++j, ++o_phdr, ++i_phdr) { |
7049 | 159 | unsigned type = get_te32(&o_phdr->p_type); |
7050 | 159 | unsigned flags = get_te32(&o_phdr->p_flags); |
7051 | 159 | if (PT_LOAD != type || !(Elf64_Phdr::PF_W & flags)) { |
7052 | 156 | continue; |
7053 | 156 | } |
7054 | 3 | unsigned filesz = get_te64(&o_phdr->p_filesz); |
7055 | 3 | unsigned o_offset = get_te64(&o_phdr->p_offset); |
7056 | 3 | unsigned i_offset = get_te64(&i_phdr->p_offset); |
7057 | 3 | fi->seek(i_offset, SEEK_SET); |
7058 | 3 | fi->readx(ibuf, filesz); |
7059 | 3 | total_in += filesz; |
7060 | 3 | if (fo) { |
7061 | 1 | fo->seek(o_offset, SEEK_SET); |
7062 | 1 | fo->write(ibuf, filesz); |
7063 | 1 | } |
7064 | 3 | total_out = filesz + o_offset; // high-water mark |
7065 | 3 | } |
7066 | | |
7067 | | // Gaps between PT_LOAD will be handled by ::unpack() |
7068 | | |
7069 | | // position fi at loader offset |
7070 | 113 | fi->seek(loader_offset, SEEK_SET); |
7071 | 113 | } |
7072 | | |
7073 | | void PackLinuxElf32::un_shlib_1( |
7074 | | OutputFile *const fo, |
7075 | | MemBuffer &o_elfhdrs, |
7076 | | unsigned &c_adler, |
7077 | | unsigned &u_adler, |
7078 | | unsigned const orig_file_size |
7079 | | ) |
7080 | 158 | { |
7081 | | // xct_off [input side] was set by ::unpack when is_shlib |
7082 | | // yct_off [output side] set here unless is_asl in next 'if' block |
7083 | 158 | unsigned yct_off = xct_off; |
7084 | | |
7085 | | // Below xct_off is not compressed (for benefit of rtld.) |
7086 | 158 | fi->seek(0, SEEK_SET); |
7087 | 158 | fi->readx(ibuf, umin(blocksize, file_size_u32)); |
7088 | | |
7089 | | // Determine if the extra page with copy of _Shdrs was spliced in. |
7090 | | // This used to be the result of --android-shlib. |
7091 | | // But in 2023-02 the forwarding of ARM_ATTRIBUTES (by appending) |
7092 | | // takes care of this, so the 5th word before e_entry does not |
7093 | | // have the low bit 1, so is_asl should not be set. |
7094 | | // However, .so that were compressed before 2023-03 |
7095 | | // may be marked. |
7096 | 158 | e_shoff = get_te32(&ehdri.e_shoff); |
7097 | 158 | if (e_shoff && e_shnum |
7098 | | // +36: (sizeof(PackHeader) + sizeof(overlay_offset)) |
7099 | | // after Shdrs for ARM_ATTRIBUTES |
7100 | 35 | && (((e_shoff + sizeof(Elf32_Shdr) * e_shnum) + 36) < file_size_u32) |
7101 | 158 | ) { // possible --android-shlib |
7102 | 15 | unsigned x = get_te32(&file_image[get_te32(&ehdri.e_entry) - (1+ 4)*sizeof(int)]); |
7103 | 15 | if (1 & x) { // the clincher |
7104 | 2 | is_asl = 1; |
7105 | 2 | fi->seek(e_shoff, SEEK_SET); |
7106 | 2 | mb_shdr.alloc( sizeof(Elf32_Shdr) * e_shnum); |
7107 | 2 | shdri = (Elf32_Shdr *)mb_shdr.getVoidPtr(); |
7108 | 2 | fi->readx(shdri, sizeof(Elf32_Shdr) * e_shnum); |
7109 | 2 | yct_off = get_te32(&shdri->sh_offset); // for the output file (de-compressed) |
7110 | 2 | xct_off = asl_delta + yct_off; // for the input file (compressed) |
7111 | 2 | } |
7112 | 15 | } |
7113 | | |
7114 | | // Decompress first Extent. Old style covers [0, xct_off) |
7115 | | // which includes rtld constant data and eXecutable app code below DT_INIT. |
7116 | | // In old style, the first compressed Extent is redundant |
7117 | | // except for the compressed original Elf headers. |
7118 | | // New style covers just Elf headers: the rest below xct_off is |
7119 | | // rtld constant data: DT_*HASH, DT_SYMTAB, DT_STRTAB, etc. |
7120 | | // New style puts eXecutable app code in second PT_LOAD |
7121 | | // in order to mark Elf headers and rtld data as non-eXecutable. |
7122 | 158 | fi->seek(overlay_offset - sizeof(l_info), SEEK_SET); |
7123 | 158 | struct { |
7124 | 158 | struct l_info l; |
7125 | 158 | struct p_info p; |
7126 | 158 | struct b_info b; |
7127 | 158 | } hdr; |
7128 | 158 | fi->readx(&hdr, sizeof(hdr)); |
7129 | 158 | if (hdr.l.l_magic != UPX_MAGIC_LE32 |
7130 | 146 | || get_te16(&hdr.l.l_lsize) != (unsigned)lsize |
7131 | 146 | || get_te32(&hdr.p.p_filesize) != ph.u_file_size |
7132 | 130 | || get_te32(&hdr.b.sz_unc) < sz_elf_hdrs // peek: 1st b_info covers Elf headers |
7133 | 158 | ) { |
7134 | 21 | throwCantUnpack("corrupt l_info/p_info/b_info"); |
7135 | 21 | } |
7136 | 137 | fi->seek(-(off_t)sizeof(struct b_info), SEEK_CUR); // hdr.b_info was a peek |
7137 | | |
7138 | | // The default layout for a shared library created by binutils-2.29 |
7139 | | // (Fedora 28; 2018) has two PT_LOAD: permissions r-x and rw-. |
7140 | | // xct_off (the lowest address of executable instructions; |
7141 | | // the highest address of read-only data used by rtld (ld-linux)) |
7142 | | // will be somewhere in the first PT_LOAD. |
7143 | | // |
7144 | | // The default layout for a shared library created by binutils-2.31 |
7145 | | // (Fedora 29; 2018) has four PT_LOAD: permissions r--, r-x, r--, rw-. |
7146 | | // xct_off will be the base of the second [r-x] PT_LOAD. |
7147 | | // |
7148 | | // Bytes below xct_off cannot be compressed because they are used |
7149 | | // by rtld *before* the UPX run-time de-compression stub gets control |
7150 | | // via DT_INIT. Bytes in a Writeable PT_LOAD cannot be compressed |
7151 | | // because they may be relocated by rtld, again before stub execution. |
7152 | | // |
7153 | | // We need to know which layout of PT_LOAD. It seems risky to steal |
7154 | | // bits in the input ElfXX_Ehdr or ElfXX_Phdr, so we decompress |
7155 | | // the first compressed block. For an old-style shared library |
7156 | | // the first compressed block covers [0, xct_off) which is redundant |
7157 | | // with the interval [sz_elf_hdrs, xct_off) because those bytes |
7158 | | // must be present for use by rtl (So that is a large inefficiency.) |
7159 | | // Fortunately p_info.p_blocksize fits in ibuf, and unpackExtent |
7160 | | // will just decompress it all. For new style, the first compressed |
7161 | | // block covers [0, sz_elf_hdrs). |
7162 | | |
7163 | | // Peek: unpack into ibuf, but do not write |
7164 | 137 | unsigned const sz_block1 = unpackExtent(sz_elf_hdrs, nullptr, |
7165 | 137 | c_adler, u_adler, false, -1); |
7166 | 137 | if (sz_block1 < sz_elf_hdrs) { |
7167 | 0 | throwCantUnpack("corrupt b_info"); |
7168 | 0 | } |
7169 | 137 | memcpy(o_elfhdrs, ibuf, sz_elf_hdrs); // save de-compressed Elf headers |
7170 | 137 | Elf32_Ehdr const *const ehdro = (Elf32_Ehdr const *)(void const *)o_elfhdrs; |
7171 | 137 | if (ehdro->e_type !=ehdri.e_type |
7172 | 103 | || ehdro->e_machine!=ehdri.e_machine |
7173 | 103 | || ehdro->e_version!=ehdri.e_version |
7174 | | // less strict for EM_PPC to workaround earlier bug |
7175 | 103 | || !( ehdro->e_flags==ehdri.e_flags |
7176 | 9 | || Elf32_Ehdr::EM_PPC == get_te16(&ehdri.e_machine)) |
7177 | 96 | || ehdro->e_ehsize !=ehdri.e_ehsize |
7178 | | // check EI_MAG[0-3], EI_CLASS, EI_DATA, EI_VERSION |
7179 | 92 | || memcmp(ehdro->e_ident, ehdri.e_ident, Elf32_Ehdr::EI_OSABI)) { |
7180 | 22 | throwCantUnpack("ElfXX_Ehdr corrupted"); |
7181 | 22 | } |
7182 | 115 | if (fo) { |
7183 | 45 | fo->write(ibuf, sz_block1); |
7184 | 45 | total_out = sz_block1; |
7185 | 45 | } |
7186 | 115 | Elf32_Phdr const *o_phdr = (Elf32_Phdr const *)(1+ ehdro); |
7187 | | // Handle compressed PT_LOADs (must not have PF_W) |
7188 | 115 | unsigned not_first_LOAD = 0; |
7189 | 281 | for (unsigned j = 0; j < e_phnum; ++j, ++o_phdr) { |
7190 | 166 | unsigned type = get_te32(&o_phdr->p_type); |
7191 | 166 | unsigned flags = get_te32(&o_phdr->p_flags); |
7192 | 166 | if (PT_LOAD != type || Elf32_Phdr::PF_W & flags) { |
7193 | 137 | continue; |
7194 | 137 | } |
7195 | 29 | unsigned p_offset = get_te32(&o_phdr->p_offset); |
7196 | 29 | unsigned p_filesz = get_te32(&o_phdr->p_filesz); |
7197 | 29 | unsigned wanted = p_filesz; |
7198 | 29 | if (!not_first_LOAD++) { // first PT_LOAD |
7199 | 29 | wanted -= sz_block1; |
7200 | 29 | if (sz_block1 > sz_elf_hdrs) { // old style |
7201 | 17 | if (is_asl) { |
7202 | 0 | un_asl_dynsym(orig_file_size, fo); |
7203 | 0 | } |
7204 | 17 | p_offset += sz_block1; |
7205 | 17 | } |
7206 | 29 | if (sz_block1 == sz_elf_hdrs) { // new style |
7207 | 12 | unsigned const len = (yct_off ? yct_off : xct_off) - sz_elf_hdrs; |
7208 | 12 | unsigned const ipos = fi->tell(); |
7209 | 12 | fi->seek(sz_elf_hdrs, SEEK_SET); |
7210 | 12 | fi->readx(&ibuf[sz_elf_hdrs], len); |
7211 | 12 | if (is_asl) { |
7212 | 0 | un_asl_dynsym(orig_file_size, nullptr); |
7213 | 0 | } |
7214 | 12 | if (fo) { |
7215 | 1 | fo->write(&ibuf[sz_elf_hdrs], len); |
7216 | 1 | } |
7217 | 12 | total_out += len; |
7218 | | |
7219 | | // github-issue629: (overlay_offset = 0xa500), so initially (xct_off = 0xa494). |
7220 | | // But "yct_off = get_te32(&shdri->sh_offset)" so if _Shdrs are aligned (??) |
7221 | | // then (0x10500 == (xct_off = asl_delta + yct_off)), and we read+write |
7222 | | // more than we need. |
7223 | | // So assume the excess just lives there, or is overwritten later by seek+write. |
7224 | 12 | if (wanted < len) { // FIXME: why does this happen? |
7225 | 0 | wanted = 0; |
7226 | 0 | } |
7227 | 12 | else { |
7228 | 12 | wanted -= len; |
7229 | 12 | } |
7230 | 12 | fi->seek(ipos, SEEK_SET); |
7231 | 12 | if (total_out == p_filesz) { |
7232 | 0 | continue; // already entirely re-generated |
7233 | 0 | } |
7234 | 12 | p_offset = total_out; |
7235 | 12 | } |
7236 | 29 | } |
7237 | 29 | if (fo) { |
7238 | 7 | fo->seek(p_offset, SEEK_SET); |
7239 | 7 | } |
7240 | 29 | unpackExtent(wanted, fo, c_adler, u_adler, false); |
7241 | 29 | } |
7242 | 115 | funpad4(fi); |
7243 | 115 | loader_offset = fi->tell(); |
7244 | | |
7245 | | // Handle PT_LOAD with PF_W: writeable, so not compressed. "Slide" |
7246 | 115 | o_phdr = (Elf32_Phdr const *)(1+ ehdro); |
7247 | 115 | Elf32_Phdr const *i_phdr = phdri; |
7248 | 243 | for (unsigned j = 0; j < e_phnum; ++j, ++o_phdr, ++i_phdr) { |
7249 | 128 | unsigned type = get_te32(&o_phdr->p_type); |
7250 | 128 | unsigned flags = get_te32(&o_phdr->p_flags); |
7251 | 128 | if (PT_LOAD != type || !(Elf32_Phdr::PF_W & flags)) { |
7252 | 127 | continue; |
7253 | 127 | } |
7254 | 1 | unsigned filesz = get_te32(&o_phdr->p_filesz); |
7255 | 1 | unsigned o_offset = get_te32(&o_phdr->p_offset); |
7256 | 1 | unsigned i_offset = get_te32(&i_phdr->p_offset); |
7257 | 1 | fi->seek(i_offset, SEEK_SET); |
7258 | 1 | fi->readx(ibuf, filesz); |
7259 | 1 | total_in += filesz; |
7260 | 1 | if (fo) { |
7261 | 1 | fo->seek(o_offset, SEEK_SET); |
7262 | 1 | fo->write(ibuf, filesz); |
7263 | 1 | } |
7264 | 1 | total_out = filesz + o_offset; // high-water mark |
7265 | 1 | } |
7266 | | |
7267 | | // Gaps between PT_LOAD will be handled by ::unpack() |
7268 | | |
7269 | | // position fi at loader offset |
7270 | 115 | fi->seek(loader_offset, SEEK_SET); |
7271 | 115 | } |
7272 | | |
7273 | | void PackLinuxElf32::un_DT_INIT( |
7274 | | unsigned old_dtinit, |
7275 | | Elf32_Phdr const *const phdro, |
7276 | | Elf32_Phdr const *const dynhdr, // in phdri |
7277 | | OutputFile *fo |
7278 | | ) |
7279 | 2 | { |
7280 | | // DT_INIT must be restored. |
7281 | | // If android_shlib, then the asl_delta relocations must be un-done. |
7282 | 2 | unsigned n_plt = 0; |
7283 | 2 | upx_uint32_t dt_pltrelsz(0), dt_jmprel(0), dt_pltgot(0); |
7284 | 2 | upx_uint32_t dt_relsz(0), dt_rel(0); |
7285 | 2 | upx_uint32_t const dyn_len = get_te32(&dynhdr->p_filesz); |
7286 | 2 | upx_uint32_t const dyn_off = get_te32(&dynhdr->p_offset); |
7287 | 2 | if (file_size_u32 < (dyn_len + dyn_off)) { |
7288 | 0 | char msg[50]; snprintf(msg, sizeof(msg), |
7289 | 0 | "bad PT_DYNAMIC .p_filesz %#lx", (long unsigned)dyn_len); |
7290 | 0 | throwCantUnpack(msg); |
7291 | 0 | } |
7292 | 2 | fi->seek(dyn_off, SEEK_SET); |
7293 | 2 | fi->readx(ibuf, dyn_len); |
7294 | 2 | Elf32_Dyn *dyn = (Elf32_Dyn *)(void *)ibuf; |
7295 | 2 | dynseg = dyn; invert_pt_dynamic(dynseg, |
7296 | 2 | umin(dyn_len, file_size_u32 - dyn_off)); |
7297 | 2 | for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { |
7298 | 0 | upx_uint32_t const tag = get_te32(&dyn->d_tag); |
7299 | 0 | upx_uint32_t val = get_te32(&dyn->d_val); |
7300 | 0 | if (is_asl) switch (tag) { |
7301 | 0 | case Elf32_Dyn::DT_RELASZ: { dt_relsz = val; } break; |
7302 | 0 | case Elf32_Dyn::DT_RELA: { dt_rel = val; } break; |
7303 | 0 | case Elf32_Dyn::DT_JMPREL: { dt_jmprel = val; } break; |
7304 | 0 | case Elf32_Dyn::DT_PLTRELSZ: { dt_pltrelsz = val; |
7305 | 0 | n_plt = dt_pltrelsz / sizeof(Elf32_Rel); |
7306 | 0 | if (is_asl) { |
7307 | 0 | n_plt += 3; // FIXME |
7308 | 0 | } |
7309 | 0 | }; break; |
7310 | | |
7311 | 0 | case Elf32_Dyn::DT_PLTGOT: { plt_va = dt_pltgot = val; (void)dt_pltgot; } |
7312 | | // FALL THROUGH |
7313 | 0 | case Elf32_Dyn::DT_PREINIT_ARRAY: |
7314 | 0 | case Elf32_Dyn::DT_INIT_ARRAY: |
7315 | 0 | case Elf32_Dyn::DT_FINI_ARRAY: |
7316 | 0 | case Elf32_Dyn::DT_FINI: if (is_asl) { |
7317 | 0 | set_te32(&dyn->d_val, val - asl_delta); |
7318 | 0 | }; break; |
7319 | 0 | } // end switch() on tag when is_asl |
7320 | 0 | if (upx_dt_init == tag) { |
7321 | 0 | if (Elf32_Dyn::DT_INIT == tag) { // the easy case |
7322 | 0 | set_te32(&dyn->d_val, old_dtinit); |
7323 | 0 | if (!old_dtinit) { // compressor took the slot |
7324 | 0 | dyn->d_tag = Elf32_Dyn::DT_NULL; |
7325 | 0 | dyn->d_val = 0; |
7326 | 0 | } |
7327 | 0 | } |
7328 | | // Apparently the hard case is common for some Android IDEs. |
7329 | 0 | else if (Elf32_Dyn::DT_INIT_ARRAY == tag |
7330 | 0 | || Elf32_Dyn::DT_PREINIT_ARRAY == tag) { |
7331 | | // 'val' is the RVA of the first slot, which is the slot that |
7332 | | // the compressor changed to be the entry to the run-time stub. |
7333 | 0 | Elf32_Dyn *dyn_null = elf_find_dynptr(Elf32_Dyn::DT_NULL); |
7334 | 0 | if (!dyn_null) |
7335 | 0 | throwCantUnpack("bad PT_DYNAMIC .end"); |
7336 | 0 | Elf32_Rel *rp = (Elf32_Rel *)elf_find_dynamic(dyn_null->d_val); |
7337 | 0 | dyn_null->d_val = 0; |
7338 | 0 | if (rp) { |
7339 | | // Compressor saved the original *rp in dynsym[0] |
7340 | 0 | Elf32_Rel *rp_unc = (Elf32_Rel *)&dynsym[0]; // pointer |
7341 | 0 | rp->r_info = rp_unc->r_info; // restore original r_info; r_offset not touched |
7342 | |
|
7343 | 0 | unsigned e_entry = get_te32(&ehdri.e_entry); |
7344 | 0 | unsigned init_rva = get_te32(&file_image[e_entry - 3*sizeof(unsigned)]); |
7345 | 0 | unsigned arr_rva = get_te32(&rp_unc->r_offset); |
7346 | 0 | Elf32_Phdr const *phdr = elf_find_Phdr_for_va(arr_rva, phdro, e_phnum); |
7347 | 0 | unsigned arr_off = (arr_rva - get_te32(&phdr->p_vaddr)) + get_te32(&phdr->p_offset); |
7348 | |
|
7349 | 0 | rp_unc->r_offset = 0; rp_unc->r_info = 0; |
7350 | 0 | if (fo) { |
7351 | 0 | fo->seek(elf_unsigned_dynamic(Elf32_Dyn::DT_SYMTAB), SEEK_SET); |
7352 | 0 | fo->rewrite(rp_unc, sizeof(Elf32_Rel)); // clear dynsym[0] |
7353 | |
|
7354 | 0 | fo->seek((char *)rp - (char *)&file_image[0], SEEK_SET); |
7355 | 0 | fo->rewrite(rp, sizeof(*rp)); // restore original *rp |
7356 | 0 | } |
7357 | | |
7358 | | // Set arr[0] to the first user init routine. |
7359 | 0 | unsigned r_info = get_te32(&rp->r_info); |
7360 | 0 | unsigned r_type = ELF32_R_TYPE(r_info); |
7361 | 0 | unsigned word; |
7362 | 0 | if (Elf32_Ehdr::EM_ARM == e_machine) { |
7363 | 0 | if (R_ARM_RELATIVE == r_type) { |
7364 | 0 | set_te32(&word, init_rva); |
7365 | 0 | } |
7366 | 0 | else if (R_ARM_ABS32 == r_type) { |
7367 | 0 | word = 0; |
7368 | 0 | } |
7369 | 0 | else { |
7370 | 0 | char msg[40]; snprintf(msg, sizeof(msg), "unknown relocation: %#x", |
7371 | 0 | r_type); |
7372 | 0 | throwCantUnpack(msg); |
7373 | 0 | } |
7374 | 0 | } |
7375 | 0 | else if (Elf32_Ehdr::EM_386 == e_machine) { |
7376 | 0 | if (R_386_RELATIVE == r_type) { |
7377 | 0 | } |
7378 | 0 | else if (R_386_32 == r_type) { |
7379 | 0 | } |
7380 | 0 | if (R_386_RELATIVE == r_type) { |
7381 | 0 | set_te32(&word, init_rva); |
7382 | 0 | } |
7383 | 0 | else if (R_386_32 == r_type) { |
7384 | 0 | word = 0; |
7385 | 0 | } |
7386 | 0 | else { |
7387 | 0 | char msg[40]; snprintf(msg, sizeof(msg), "unknown relocation: %#x", |
7388 | 0 | r_type); |
7389 | 0 | throwCantUnpack(msg); |
7390 | 0 | } |
7391 | 0 | } |
7392 | 0 | if (fo) { |
7393 | 0 | fo->seek(arr_off, SEEK_SET); |
7394 | 0 | fo->rewrite(&word, sizeof(unsigned)); |
7395 | 0 | fo->seek(0, SEEK_END); |
7396 | 0 | } |
7397 | 0 | } |
7398 | 0 | } |
7399 | 0 | } |
7400 | 0 | } |
7401 | 2 | if (fo) { // Write updated dt_*.val |
7402 | 0 | upx_uint32_t dyn_offo = get_te32(&phdro[dynhdr - phdri].p_offset); |
7403 | 0 | fo->seek(dyn_offo, SEEK_SET); |
7404 | 0 | fo->rewrite(ibuf, dyn_len); |
7405 | 0 | } |
7406 | 2 | if (is_asl) { |
7407 | 0 | MemBuffer ptload1; // FIXME. file_image has the whole file; ibuf is available |
7408 | 0 | lowmem.alloc(xct_off); |
7409 | 0 | fi->seek(0, SEEK_SET); |
7410 | 0 | fi->read(lowmem, xct_off); // contains relocation tables |
7411 | 0 | if (dt_relsz && dt_rel) { |
7412 | 0 | Elf32_Rel *const rel0 = (Elf32_Rel *)lowmem.subref( |
7413 | 0 | "bad Rel offset", dt_rel, dt_relsz); |
7414 | 0 | unRel32(dt_rel, rel0, dt_relsz, ptload1, old_dtinit, fo); |
7415 | 0 | } |
7416 | 0 | if (dt_pltrelsz && dt_jmprel) { // FIXME: overlap w/ DT_REL ? |
7417 | 0 | Elf32_Rel *const jmp0 = (Elf32_Rel *)lowmem.subref( |
7418 | 0 | "bad Jmprel offset", dt_jmprel, dt_pltrelsz); |
7419 | 0 | jump_slots.alloc(n_plt * sizeof(upx_uint32_t)); |
7420 | 0 | Elf32_Phdr const *phdr = phdri; |
7421 | 0 | for (unsigned j = 0; j < e_phnum; ++j, ++phdr) if (is_LOAD(phdr)) { |
7422 | 0 | upx_uint32_t vaddr = get_te32(&phdr->p_vaddr); |
7423 | 0 | upx_uint32_t filesz = get_te32(&phdr->p_filesz); |
7424 | 0 | upx_uint32_t d = plt_va - vaddr; |
7425 | 0 | if (d < filesz) { |
7426 | 0 | upx_uint32_t offset = get_te32(&phdr->p_offset); |
7427 | 0 | fi->seek(d + offset, SEEK_SET); |
7428 | 0 | fi->readx(jump_slots, n_plt * sizeof(upx_uint32_t)); |
7429 | 0 | break; |
7430 | 0 | } |
7431 | 0 | } |
7432 | 0 | unRel32(dt_jmprel, jmp0, dt_pltrelsz, ptload1, old_dtinit, fo); |
7433 | |
|
7434 | 0 | Elf32_Ehdr const *const o_ehdr = (Elf32_Ehdr const *)(void *)lowmem; |
7435 | 0 | unsigned const o_phnum = o_ehdr->e_phnum; |
7436 | 0 | if (((1<<16) - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr) < o_phnum) |
7437 | 0 | throwCantUnpack("bad Ehdr.e_phnum %#x", o_phnum); |
7438 | 0 | phdr = phdro; |
7439 | 0 | for (unsigned j = 0; j < o_phnum; ++j, ++phdr) if (is_LOAD(phdr)) { |
7440 | 0 | upx_uint32_t vaddr = get_te32(&phdr->p_vaddr); |
7441 | 0 | upx_uint32_t filesz = get_te32(&phdr->p_filesz); |
7442 | 0 | upx_uint32_t d = plt_va - vaddr - asl_delta; |
7443 | 0 | if (d < filesz) { |
7444 | 0 | upx_uint32_t offset = get_te32(&phdr->p_offset); |
7445 | 0 | if ((upx_uint32_t)file_size <= offset) |
7446 | 0 | throwCantUnpack("bad phdr[%d].p_offset %#zx", j, (size_t)offset); |
7447 | 0 | if (fo) { |
7448 | 0 | fo->seek(d + offset, SEEK_SET); |
7449 | 0 | fo->rewrite(jump_slots, n_plt * sizeof(upx_uint32_t)); |
7450 | 0 | } |
7451 | 0 | break; |
7452 | 0 | } |
7453 | 0 | } |
7454 | 0 | } |
7455 | | // Modified relocation tables are re-written by unRel32 |
7456 | 0 | } |
7457 | 2 | } |
7458 | | |
7459 | | void PackLinuxElf64::un_DT_INIT( |
7460 | | unsigned old_dtinit, |
7461 | | Elf64_Phdr const *const phdro, |
7462 | | Elf64_Phdr const *const dynhdr, // in phdri |
7463 | | OutputFile *fo |
7464 | | ) |
7465 | 7 | { |
7466 | | // DT_INIT must be restored. |
7467 | | // If android_shlib, then the asl_delta relocations must be un-done. |
7468 | 7 | unsigned n_plt = 0; |
7469 | 7 | upx_uint64_t dt_pltrelsz(0), dt_jmprel(0), dt_pltgot(0); |
7470 | 7 | upx_uint64_t dt_relasz(0), dt_rela(0); |
7471 | 7 | upx_uint64_t const dyn_len = get_te64(&dynhdr->p_filesz); |
7472 | 7 | upx_uint64_t const dyn_off = get_te64(&dynhdr->p_offset); |
7473 | 7 | if (file_size_u < (dyn_len + dyn_off)) { |
7474 | 5 | char msg[50]; snprintf(msg, sizeof(msg), |
7475 | 5 | "bad PT_DYNAMIC .p_filesz %#lx", (long unsigned)dyn_len); |
7476 | 5 | throwCantUnpack(msg); |
7477 | 5 | } |
7478 | 2 | fi->seek(dyn_off, SEEK_SET); |
7479 | 2 | fi->readx(ibuf, dyn_len); |
7480 | 2 | Elf64_Dyn *dyn = (Elf64_Dyn *)(void *)ibuf; |
7481 | 2 | dynseg = dyn; invert_pt_dynamic(dynseg, |
7482 | 2 | umin(dyn_len, file_size_u - dyn_off)); |
7483 | 2 | for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { |
7484 | 0 | upx_uint64_t const tag = get_te64(&dyn->d_tag); |
7485 | 0 | upx_uint64_t val = get_te64(&dyn->d_val); |
7486 | 0 | if (is_asl) switch (tag) { |
7487 | 0 | case Elf64_Dyn::DT_RELASZ: { dt_relasz = val; } break; |
7488 | 0 | case Elf64_Dyn::DT_RELA: { dt_rela = val; } break; |
7489 | 0 | case Elf64_Dyn::DT_JMPREL: { dt_jmprel = val; } break; |
7490 | 0 | case Elf64_Dyn::DT_PLTRELSZ: { dt_pltrelsz = val; |
7491 | 0 | n_plt = dt_pltrelsz / sizeof(Elf32_Rel); |
7492 | 0 | if (is_asl) { |
7493 | 0 | n_plt += 3; // FIXME |
7494 | 0 | } |
7495 | 0 | }; break; |
7496 | | |
7497 | 0 | case Elf64_Dyn::DT_PLTGOT: { plt_va = dt_pltgot = val; (void)dt_pltgot;} |
7498 | | // FALL THROUGH |
7499 | 0 | case Elf64_Dyn::DT_PREINIT_ARRAY: |
7500 | 0 | case Elf64_Dyn::DT_INIT_ARRAY: |
7501 | 0 | case Elf64_Dyn::DT_FINI_ARRAY: |
7502 | 0 | case Elf64_Dyn::DT_FINI: if (is_asl) { |
7503 | 0 | set_te64(&dyn->d_val, val - asl_delta); |
7504 | 0 | }; break; |
7505 | 0 | } // end switch() on tag when is_asl |
7506 | 0 | if (upx_dt_init == tag) { // the easy case |
7507 | 0 | if (Elf64_Dyn::DT_INIT == tag) { |
7508 | 0 | set_te64(&dyn->d_val, old_dtinit); |
7509 | 0 | if (!old_dtinit) { // compressor took the slot |
7510 | 0 | dyn->d_tag = Elf64_Dyn::DT_NULL; |
7511 | 0 | dyn->d_val = 0; |
7512 | 0 | } |
7513 | 0 | } |
7514 | | // Apparently the hard case is common for some Android IDEs. |
7515 | | // No DT_INIT; only DT_INIT_ARRAY. |
7516 | 0 | else if (Elf64_Dyn::DT_INIT_ARRAY == tag |
7517 | 0 | || Elf64_Dyn::DT_PREINIT_ARRAY == tag) { |
7518 | | // 'val' is the RVA of the first slot, which is the slot that |
7519 | | // the compressor changed to be the entry to the run-time stub. |
7520 | 0 | Elf64_Dyn *dyn_null = elf_find_dynptr(Elf64_Dyn::DT_NULL); |
7521 | 0 | if (!dyn_null) |
7522 | 0 | throwCantUnpack("bad PT_DYNAMIC .end"); |
7523 | 0 | Elf64_Rela *rp = (Elf64_Rela *)elf_find_dynamic(dyn_null->d_val); |
7524 | 0 | dyn_null->d_val = 0; |
7525 | 0 | if (rp) { |
7526 | | // Compressor saved the original *rp in dynsym[0] |
7527 | 0 | Elf64_Rela *rp_unc = (Elf64_Rela *)&dynsym[0]; // pointer |
7528 | 0 | rp->r_info = rp_unc->r_info; // restore original r_info; r_offset not touched |
7529 | 0 | rp->r_addend = rp_unc->r_addend; |
7530 | |
|
7531 | 0 | unsigned arr_rva = get_te64(&rp_unc->r_offset); |
7532 | 0 | Elf64_Phdr const *phdr = elf_find_Phdr_for_va(arr_rva, phdro, e_phnum); |
7533 | 0 | unsigned arr_off = (arr_rva - get_te64(&phdr->p_vaddr)) + get_te64(&phdr->p_offset); |
7534 | |
|
7535 | 0 | if (fo) { |
7536 | 0 | memset(rp_unc, 0, sizeof(*rp_unc)); |
7537 | 0 | fo->seek(elf_unsigned_dynamic(Elf64_Dyn::DT_SYMTAB), SEEK_SET); |
7538 | 0 | fo->rewrite(rp_unc, sizeof(Elf64_Rela)); // clear dynsym[0] |
7539 | |
|
7540 | 0 | fo->seek((char *)rp - (char *)&file_image[0], SEEK_SET); |
7541 | 0 | fo->rewrite(rp, sizeof(*rp)); // restore original *rp |
7542 | | |
7543 | | // Elf64_Rela overwrites; but put back original. |
7544 | 0 | fo->seek(arr_off, SEEK_SET); |
7545 | 0 | fo->rewrite(rp_unc, sizeof(u64_t)); |
7546 | |
|
7547 | 0 | fo->seek(0, SEEK_END); |
7548 | 0 | } |
7549 | 0 | } |
7550 | 0 | } |
7551 | 0 | } |
7552 | 0 | } |
7553 | 2 | if (fo) { // Write updated dt_*.val |
7554 | 0 | upx_uint64_t dyn_offo = get_te64(&phdro[dynhdr - phdri].p_offset); |
7555 | 0 | fo->seek(dyn_offo, SEEK_SET); |
7556 | 0 | fo->rewrite(ibuf, dyn_len); |
7557 | 0 | } |
7558 | 2 | if (is_asl) { |
7559 | 0 | lowmem.alloc(xct_off); |
7560 | 0 | fi->seek(0, SEEK_SET); |
7561 | 0 | fi->read(lowmem, xct_off); // contains relocation tables |
7562 | 0 | if (dt_relasz && dt_rela) { |
7563 | 0 | Elf64_Rela *const rela0 = (Elf64_Rela *)lowmem.subref( |
7564 | 0 | "bad Rela offset", dt_rela, dt_relasz); |
7565 | 0 | unRela64(dt_rela, rela0, dt_relasz, old_dtinit, fo); |
7566 | 0 | } |
7567 | 0 | if (dt_pltrelsz && dt_jmprel) { // FIXME: overlap w/ DT_REL ? |
7568 | 0 | Elf64_Rela *const jmp0 = (Elf64_Rela *)lowmem.subref( |
7569 | 0 | "bad Jmprel offset", dt_jmprel, dt_pltrelsz); |
7570 | 0 | jump_slots.alloc(n_plt * sizeof(upx_uint64_t)); |
7571 | 0 | Elf64_Phdr const *phdr = phdri; |
7572 | 0 | for (unsigned j = 0; j < e_phnum; ++j, ++phdr) if (is_LOAD(phdr)) { |
7573 | 0 | upx_uint64_t vaddr = get_te64(&phdr->p_vaddr); |
7574 | 0 | upx_uint64_t filesz = get_te64(&phdr->p_filesz); |
7575 | 0 | upx_uint64_t d = plt_va - vaddr; |
7576 | 0 | if (d < filesz) { |
7577 | 0 | upx_uint64_t offset = get_te64(&phdr->p_offset); |
7578 | 0 | fi->seek(d + offset, SEEK_SET); |
7579 | 0 | fi->readx(jump_slots, n_plt * sizeof(upx_uint64_t)); |
7580 | 0 | break; |
7581 | 0 | } |
7582 | 0 | } |
7583 | 0 | unRela64(dt_jmprel, jmp0, dt_pltrelsz, old_dtinit, fo); |
7584 | |
|
7585 | 0 | Elf64_Ehdr const *const o_ehdr = (Elf64_Ehdr const *)(void *)lowmem; |
7586 | 0 | unsigned const o_phnum = o_ehdr->e_phnum; |
7587 | 0 | if (((1<<16) - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr) < o_phnum) |
7588 | 0 | throwCantUnpack("bad Ehdr.e_phnum %#x", o_phnum); |
7589 | 0 | phdr = phdro; |
7590 | 0 | for (unsigned j = 0; j < o_phnum; ++j, ++phdr) if (is_LOAD(phdr)) { |
7591 | 0 | upx_uint64_t vaddr = get_te64(&phdr->p_vaddr); |
7592 | 0 | upx_uint64_t filesz = get_te64(&phdr->p_filesz); |
7593 | 0 | upx_uint64_t d = plt_va - vaddr - asl_delta; |
7594 | 0 | if (d < filesz) { |
7595 | 0 | upx_uint64_t offset = get_te64(&phdr->p_offset); |
7596 | 0 | if ((upx_uint64_t)file_size <= offset) |
7597 | 0 | throwCantUnpack("bad phdr[%d].p_offset %#zx", j, (size_t)offset); |
7598 | 0 | if (fo) { |
7599 | 0 | fo->seek(d + offset, SEEK_SET); |
7600 | 0 | fo->rewrite(jump_slots, n_plt * sizeof(upx_uint64_t)); |
7601 | 0 | } |
7602 | 0 | break; |
7603 | 0 | } |
7604 | 0 | } |
7605 | 0 | } |
7606 | | // Modified relocation tables are re-written by unRela64 |
7607 | 0 | } |
7608 | 2 | } |
7609 | | |
7610 | | void PackLinuxElf64::unpack(OutputFile *fo) |
7611 | 794 | { |
7612 | 794 | if (e_phoff != sizeof(Elf64_Ehdr)) {// Phdrs not contiguous with Ehdr |
7613 | 0 | throwCantUnpack("bad e_phoff"); |
7614 | 0 | } |
7615 | 794 | unsigned const c_phnum = get_te16(&ehdri.e_phnum); |
7616 | 794 | unsigned u_phnum = 0; |
7617 | 794 | upx_uint64_t old_dtinit = 0; |
7618 | | |
7619 | 794 | if (Elf64_Ehdr::ET_EXEC == get_te16(&ehdri.e_type)) { |
7620 | | // 40fddf17153ee3db73a04ff1bf288b91676138d6 2001-02-01 ph.version 11; b_info 12 bytes |
7621 | | // df9db96bd1c013c07da1d7ec740021d588ab2815 2001-01-17 ph.version 11; no b_info (==> 8 bytes) |
7622 | 768 | if (ph.version <= 11 |
7623 | 34 | && get_te64(&ehdri.e_entry) < 0x401180 |
7624 | 7 | && get_te16(&ehdri.e_machine)==Elf64_Ehdr::EM_X86_64) { |
7625 | | // old style, 8-byte b_info: |
7626 | | // sizeof(b_info.sz_unc) + sizeof(b_info.sz_cpr); |
7627 | 7 | szb_info = 2*sizeof(unsigned); |
7628 | 7 | } |
7629 | 768 | } |
7630 | | |
7631 | 794 | fi->seek(overlay_offset - sizeof(l_info), SEEK_SET); |
7632 | 794 | fi->readx(&linfo, sizeof(linfo)); |
7633 | 794 | if (UPX_MAGIC_LE32 != get_le32(&linfo.l_magic)) { |
7634 | 123 | NE32 const *const lp = (NE32 const *)(void const *)&linfo; |
7635 | | // Workaround for bug of extra linfo by some asl_pack2_Shdrs(). |
7636 | 123 | if (0==lp[0] && 0==lp[1] && 0==lp[2]) { // looks like blank extra |
7637 | 8 | fi->readx(&linfo, sizeof(linfo)); |
7638 | 8 | if (UPX_MAGIC_LE32 == get_le32(&linfo.l_magic)) { |
7639 | 2 | overlay_offset += sizeof(linfo); |
7640 | 2 | } |
7641 | 6 | else { |
7642 | 6 | throwCantUnpack("l_info corrupted"); |
7643 | 6 | } |
7644 | 8 | } |
7645 | 115 | else { |
7646 | 115 | throwCantUnpack("l_info corrupted"); |
7647 | 115 | } |
7648 | 123 | } |
7649 | 673 | lsize = get_te16(&linfo.l_lsize); |
7650 | 673 | p_info hbuf; fi->readx(&hbuf, sizeof(hbuf)); |
7651 | 673 | unsigned orig_file_size = get_te32(&hbuf.p_filesize); |
7652 | 673 | blocksize = get_te32(&hbuf.p_blocksize); |
7653 | 673 | if ((u32_t)file_size > orig_file_size || blocksize > orig_file_size |
7654 | 631 | || (orig_file_size >> 8) > (u32_t)file_size // heuristic anti-fuzz |
7655 | 591 | || (blocksize >> 8) > (u32_t)file_size |
7656 | 591 | || !mem_size_valid(1, blocksize, OVERHEAD)) |
7657 | 79 | throwCantUnpack("p_info corrupted"); |
7658 | | |
7659 | 594 | ibuf.alloc(blocksize + OVERHEAD); |
7660 | 594 | b_info bhdr; memset(&bhdr, 0, sizeof(bhdr)); |
7661 | 594 | fi->readx(&bhdr, szb_info); |
7662 | 594 | ph.u_len = get_te32(&bhdr.sz_unc); |
7663 | 594 | ph.c_len = get_te32(&bhdr.sz_cpr); |
7664 | 594 | ph.set_method(bhdr.b_method, overlay_offset + sizeof(p_info)); |
7665 | 594 | if (ph.c_len > file_size_u || ph.c_len == 0 || ph.u_len == 0 |
7666 | 584 | || ph.u_len > orig_file_size) |
7667 | 20 | throwCantUnpack("b_info corrupted"); |
7668 | 574 | ph.filter_cto = bhdr.b_cto8; |
7669 | 574 | prev_method = bhdr.b_method; // FIXME if multiple de-compressors |
7670 | | |
7671 | 574 | MemBuffer u(ph.u_len); |
7672 | 574 | Elf64_Ehdr *const ehdr = (Elf64_Ehdr *)&u[0]; |
7673 | 574 | Elf64_Phdr const *phdr = nullptr; |
7674 | 574 | total_in = 0; |
7675 | 574 | total_out = 0; |
7676 | 574 | unsigned c_adler = upx_adler32(nullptr, 0); |
7677 | 574 | unsigned u_adler = upx_adler32(nullptr, 0); |
7678 | | |
7679 | 574 | unsigned is_shlib = 0; |
7680 | 574 | loader_offset = 0; |
7681 | 574 | MemBuffer o_elfhdrs; |
7682 | 574 | Elf64_Phdr const *const dynhdr = elf_find_ptype(Elf64_Phdr::PT_DYNAMIC, phdri, c_phnum); |
7683 | | // dynseg was set by PackLinuxElf64help1 |
7684 | 574 | if (dynhdr && !(Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1))) { |
7685 | | // Packed shlib? (ET_DYN without -fPIE) |
7686 | 185 | is_shlib = 1; |
7687 | 185 | xct_off = overlay_offset - sizeof(l_info); |
7688 | 185 | u_phnum = get_te16(&ehdri.e_phnum); |
7689 | 185 | o_elfhdrs.alloc(sz_elf_hdrs); |
7690 | 185 | un_shlib_1(fo, o_elfhdrs, c_adler, u_adler, orig_file_size); |
7691 | 185 | *ehdr = ehdri; |
7692 | 185 | } |
7693 | 389 | else { // main executable |
7694 | | // Uncompress Ehdr and Phdrs: info for control of unpacking |
7695 | 389 | if (ibuf.getSize() < ph.c_len) |
7696 | 1 | throwCompressedDataViolation(); |
7697 | | |
7698 | 388 | fi->readx(ibuf, ph.c_len); |
7699 | | // "clickhouse" ET_EXEC for amd64 has 0x200000 <= .e_entry |
7700 | | // instead of 0x400000 that we checked earlier. |
7701 | 388 | if (8 == szb_info |
7702 | 0 | && Elf64_Ehdr::EM_X86_64 == e_machine |
7703 | 0 | && Elf64_Ehdr::ET_EXEC == e_type |
7704 | 0 | && ph.u_len <= MAX_ELF_HDR_64 |
7705 | 388 | ) { |
7706 | 0 | unsigned b_method = ibuf[0]; |
7707 | 0 | unsigned b_extra = ibuf[3]; |
7708 | 0 | if (M_ZSTD >= b_method && 0 == b_extra) { |
7709 | 0 | unsigned where = fi->seek( -(upx_off_t)(ph.c_len + szb_info), SEEK_CUR); |
7710 | 0 | szb_info = 12; |
7711 | 0 | fi->readx(&bhdr, szb_info); |
7712 | 0 | ph.filter_cto = bhdr.b_cto8; |
7713 | 0 | ph.set_method(bhdr.b_method, where); |
7714 | 0 | prev_method = bhdr.b_method; // FIXME if multiple de-compressors |
7715 | 0 | fi->readx(ibuf, ph.c_len); |
7716 | 0 | } |
7717 | 0 | } |
7718 | 388 | if (ph.u_len < sizeof(*ehdr)) |
7719 | 2 | throwCantUnpack("ElfXX_Ehdr corrupted"); |
7720 | 386 | decompress(ibuf, (upx_byte *)ehdr, false); |
7721 | 386 | if (ehdr->e_type !=ehdri.e_type |
7722 | 352 | || ehdr->e_machine!=ehdri.e_machine |
7723 | 352 | || ehdr->e_version!=ehdri.e_version |
7724 | | // less strict for EM_PPC64 to workaround earlier bug |
7725 | 352 | || !( ehdr->e_flags==ehdri.e_flags |
7726 | 6 | || Elf64_Ehdr::EM_PPC64 == get_te16(&ehdri.e_machine)) |
7727 | 348 | || ehdr->e_ehsize !=ehdri.e_ehsize |
7728 | | // check EI_MAG[0-3], EI_CLASS, EI_DATA, EI_VERSION |
7729 | 345 | || memcmp(ehdr->e_ident, ehdri.e_ident, Elf64_Ehdr::EI_OSABI)) { |
7730 | 12 | throwCantUnpack("ElfXX_Ehdr corrupted"); |
7731 | 12 | } |
7732 | | // Rewind: prepare for data phase |
7733 | 374 | fi->seek(- (off_t) (szb_info + ph.c_len), SEEK_CUR); |
7734 | | |
7735 | 374 | u_phnum = get_te16(&ehdr->e_phnum); |
7736 | 374 | if ((umin(MAX_ELF_HDR_64, ph.u_len) - sizeof(Elf64_Ehdr))/sizeof(Elf64_Phdr) < u_phnum) { |
7737 | 0 | throwCantUnpack("bad compressed e_phnum"); |
7738 | 0 | } |
7739 | 374 | o_elfhdrs.alloc(sizeof(Elf64_Ehdr) + u_phnum * sizeof(Elf64_Phdr)); |
7740 | 374 | memcpy(o_elfhdrs, ehdr, o_elfhdrs.getSize()); |
7741 | | |
7742 | | // Decompress each PT_LOAD. |
7743 | 374 | bool first_PF_X = true; |
7744 | 374 | phdr = (Elf64_Phdr *) (void *) (1+ ehdr); // uncompressed |
7745 | 1.67k | for (unsigned j=0; j < u_phnum; ++phdr, ++j) { |
7746 | 1.30k | if (is_LOAD(phdr)) { |
7747 | 457 | unsigned const filesz = get_te64(&phdr->p_filesz); |
7748 | 457 | unsigned const offset = get_te64(&phdr->p_offset); |
7749 | 457 | if (fo) { |
7750 | 251 | fo->seek(offset, SEEK_SET); |
7751 | 251 | if (total_out < offset) { |
7752 | 83 | total_out = offset; // FIXME: can it be re-write? |
7753 | 83 | } |
7754 | 251 | } |
7755 | 457 | if (Elf64_Phdr::PF_X & get_te32(&phdr->p_flags)) { |
7756 | 262 | unpackExtent(filesz, fo, |
7757 | 262 | c_adler, u_adler, first_PF_X); |
7758 | 262 | first_PF_X = false; |
7759 | 262 | } |
7760 | 195 | else { |
7761 | 195 | unpackExtent(filesz, fo, |
7762 | 195 | c_adler, u_adler, false); |
7763 | 195 | } |
7764 | 457 | } |
7765 | 1.30k | } |
7766 | 374 | } |
7767 | | |
7768 | 559 | upx_uint64_t const e_entry = get_te64(&ehdri.e_entry); |
7769 | 559 | unsigned off_entry = 0; |
7770 | 559 | phdr = phdri; |
7771 | 559 | load_va = 0; |
7772 | 18.9k | for (unsigned j=0; j < c_phnum; ++j, ++phdr) { |
7773 | 18.5k | if (is_LOAD(phdr)) { |
7774 | 555 | upx_uint64_t offset = get_te64(&phdr->p_offset); |
7775 | 555 | upx_uint64_t vaddr = get_te64(&phdr->p_vaddr); |
7776 | 555 | upx_uint64_t filesz = get_te64(&phdr->p_filesz); |
7777 | 555 | if (!load_va) { |
7778 | 293 | load_va = vaddr; |
7779 | 293 | } |
7780 | 555 | if ((e_entry - vaddr) < filesz) { |
7781 | 129 | off_entry = (e_entry - vaddr) + offset; |
7782 | 129 | break; |
7783 | 129 | } |
7784 | 555 | } |
7785 | 18.5k | } |
7786 | 559 | unsigned d_info[6]; |
7787 | 559 | unsigned sz_d_info = sizeof(d_info); |
7788 | 559 | if (!is_shlib) { |
7789 | 178 | if (get_te32(&phdri[0].p_flags) & Elf64_Phdr::PF_X) { |
7790 | | // Old style, such as upx-3.91 thru upx-3.95 |
7791 | 79 | switch (this->e_machine) { |
7792 | 0 | default: { |
7793 | 0 | char msg[40]; snprintf(msg, sizeof(msg), |
7794 | 0 | "Unknown architecture %d", this->e_machine); |
7795 | 0 | throwCantUnpack(msg); |
7796 | 0 | }; break; |
7797 | 4 | case Elf64_Ehdr::EM_AARCH64: sz_d_info = 4 * sizeof(unsigned); break; |
7798 | 9 | case Elf64_Ehdr::EM_PPC64: sz_d_info = 3 * sizeof(unsigned); break; |
7799 | 66 | case Elf64_Ehdr::EM_X86_64: sz_d_info = 2 * sizeof(unsigned); break; |
7800 | 79 | } |
7801 | 79 | } |
7802 | 178 | loader_offset = off_entry - sz_d_info; |
7803 | 178 | } |
7804 | | |
7805 | 559 | if (0x1000==get_te64(&phdri[0].p_filesz) // detect C_BASE style |
7806 | 89 | && 0==get_te64(&phdri[1].p_offset) |
7807 | 80 | && 0==get_te64(&phdri[0].p_offset) |
7808 | 62 | && get_te64(&phdri[1].p_filesz) == get_te64(&phdri[1].p_memsz)) { |
7809 | 53 | fi->seek(up4(get_te64(&phdri[1].p_memsz)), SEEK_SET); // past the loader |
7810 | 53 | } |
7811 | 506 | else if (is_shlib |
7812 | 135 | || (off_entry + up4(lsize) + ph.getPackHeaderSize() + sizeof(overlay_offset)) |
7813 | 163 | < up4(file_size)) { |
7814 | | // Loader is not at end; skip past it. |
7815 | 163 | if (loader_offset) { |
7816 | 163 | fi->seek(loader_offset, SEEK_SET); |
7817 | 163 | } |
7818 | 0 | else { |
7819 | 0 | funpad4(fi); // MATCH01 |
7820 | 0 | } |
7821 | 163 | fi->readx(d_info, sz_d_info); |
7822 | 163 | if (is_shlib && 0==old_dtinit) { |
7823 | 63 | old_dtinit = get_te32(&d_info[2 + (0==d_info[0])]); |
7824 | 63 | is_asl = 1u& get_te32(&d_info[0 + (0==d_info[0])]); |
7825 | 63 | } |
7826 | 163 | fi->seek(lsize - sz_d_info, SEEK_CUR); |
7827 | 163 | } |
7828 | | |
7829 | | // The gaps between PT_LOAD and after last PT_LOAD |
7830 | 559 | phdr = (Elf64_Phdr const *)(1+ (Elf64_Ehdr const *)(void const *)o_elfhdrs); |
7831 | 559 | upx_uint64_t hi_offset(0); |
7832 | 1.50k | for (unsigned j = 0; j < u_phnum; ++j) { |
7833 | 943 | upx_uint64_t const offset = get_te64(&phdr[j].p_offset); |
7834 | 943 | if (is_LOAD(&phdr[j]) |
7835 | 286 | && hi_offset < offset) { |
7836 | 179 | hi_offset = offset; |
7837 | 179 | } |
7838 | 943 | } |
7839 | 1.26k | for (unsigned j = 0; j < u_phnum; ++j) { |
7840 | 749 | unsigned const size = find_LOAD_gap(phdr, j, u_phnum); |
7841 | 749 | if (size) { |
7842 | 213 | unsigned const where = get_te64(&phdr[j].p_offset) + |
7843 | 213 | get_te64(&phdr[j].p_filesz); |
7844 | 213 | if (fo) |
7845 | 96 | fo->seek(where, SEEK_SET); |
7846 | 213 | { // Recover from some piracy [also serves as error tolerance :-) ] |
7847 | | // Getting past the loader is problematic, due to unintended |
7848 | | // variances between released versions: |
7849 | | // l_info.l_lsize might be rounded up by 8 instead of by 4, and |
7850 | | // sz_d_info might have changed. |
7851 | 213 | b_info b_peek, *bp = &b_peek; |
7852 | 213 | fi->readx(bp, sizeof(b_peek)); |
7853 | 213 | upx_off_t pos = fi->seek(-(off_t)sizeof(b_peek), SEEK_CUR); |
7854 | 213 | unsigned sz_unc = get_te32(&bp->sz_unc); |
7855 | 213 | unsigned sz_cpr = get_te32(&bp->sz_cpr); |
7856 | 213 | unsigned word3 = get_te32(&bp->b_method); |
7857 | 213 | unsigned method = bp->b_method; |
7858 | 213 | unsigned ftid = bp->b_ftid; |
7859 | 213 | unsigned cto8 = bp->b_cto8; |
7860 | 213 | if (!( ((sz_cpr == sz_unc) && (0 == word3) && (size == sz_unc)) // incompressible literal |
7861 | 213 | || ((sz_cpr < sz_unc) |
7862 | 170 | && (method == prev_method || M_NRV2B_LE32 == prev_method) |
7863 | 132 | && (0 == ftid) && (0 == cto8)) ) |
7864 | 213 | ) { |
7865 | 84 | opt->info_mode++; |
7866 | 84 | infoWarning("bad b_info at %#zx", (size_t)pos); |
7867 | 84 | unsigned const N_PEEK(16 * sizeof(int)), H_PEEK(N_PEEK >> 1); |
7868 | 84 | unsigned char peek_arr[N_PEEK]; |
7869 | 84 | fi->seek(pos - H_PEEK, SEEK_SET); |
7870 | 84 | fi->readx(peek_arr, sizeof(peek_arr)); |
7871 | 84 | fi->seek(pos, SEEK_SET); |
7872 | 84 | bool const is_be = ELFDATA2MSB == ehdri.e_ident[EI_DATA]; |
7873 | 84 | if (is_be) { |
7874 | | // Does the right thing for sz_unc and sz_cpr, |
7875 | | // but swaps b_method and b_extra. Need find_be32() :-) |
7876 | 221 | for (unsigned k = 0; k < N_PEEK; k += sizeof(int)) { |
7877 | 208 | set_le32(&peek_arr[k], get_be32(&peek_arr[k])); |
7878 | 208 | } |
7879 | 13 | } |
7880 | 84 | int boff = find_le32(peek_arr, sizeof(peek_arr), size); |
7881 | 84 | if (boff < 0 |
7882 | 48 | || sizeof(peek_arr) < (boff + sizeof(b_info))) { |
7883 | 41 | throwCantUnpack("b_info corrupted"); |
7884 | 41 | } |
7885 | 43 | bp = (b_info *)(void *)&peek_arr[boff]; |
7886 | | |
7887 | 43 | sz_unc = get_le32(&bp->sz_unc); |
7888 | 43 | sz_cpr = get_le32(&bp->sz_cpr); |
7889 | 43 | word3 = get_le32(&bp->b_method); |
7890 | 43 | ftid = bp->b_ftid; |
7891 | 43 | cto8 = bp->b_cto8; |
7892 | 43 | if (0 <= boff // found |
7893 | 43 | && ( ((sz_cpr == sz_unc) && (0 == word3) && (size == sz_unc)) // incompressible literal |
7894 | 43 | || ((sz_cpr < sz_unc) && (0 == ftid) && (0 == cto8) |
7895 | 35 | && ((is_be ? bp->b_extra : bp->b_method) == prev_method)) ) |
7896 | 43 | ) { |
7897 | 30 | pos -= H_PEEK; |
7898 | 30 | pos += boff; |
7899 | 30 | infoWarning("... recovery at %#zx", (size_t)pos); |
7900 | 30 | fi->seek(pos, SEEK_SET); |
7901 | 30 | } |
7902 | 43 | opt->info_mode--; |
7903 | 43 | } |
7904 | 213 | } |
7905 | 172 | unpackExtent(size, fo, |
7906 | 172 | c_adler, u_adler, false, |
7907 | 172 | (hi_offset != get_te64(&phdr[j].p_offset))); |
7908 | 172 | } |
7909 | 749 | } |
7910 | | |
7911 | | // check for end-of-file |
7912 | 518 | fi->readx(&bhdr, szb_info); |
7913 | 518 | ph.set_method(bhdr.b_method, ~0u); |
7914 | 518 | unsigned const sz_unc = ph.u_len = get_te32(&bhdr.sz_unc); |
7915 | | |
7916 | 518 | if (sz_unc == 0) { // uncompressed size 0 -> EOF |
7917 | | // note: magic is always stored le32 |
7918 | 48 | unsigned const sz_cpr = get_le32(&bhdr.sz_cpr); |
7919 | 48 | if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic |
7920 | 11 | throwCompressedDataViolation(); |
7921 | 48 | } |
7922 | 470 | else { // extra bytes after end? |
7923 | 470 | throwCompressedDataViolation(); |
7924 | 470 | } |
7925 | | |
7926 | 37 | if (is_shlib) { |
7927 | 7 | un_DT_INIT(old_dtinit, (Elf64_Phdr *)(1+ (Elf64_Ehdr *)(void *)o_elfhdrs), dynhdr, fo); |
7928 | 7 | } |
7929 | | |
7930 | | // update header with totals |
7931 | 37 | ph.c_len = total_in; |
7932 | 37 | ph.u_len = total_out; |
7933 | | |
7934 | | // all bytes must be written |
7935 | 37 | if (fo && total_out != orig_file_size) |
7936 | 1 | throwEOFException(); |
7937 | | |
7938 | | // finally test the checksums |
7939 | 36 | if (ph.c_adler != c_adler || ph.u_adler != u_adler) |
7940 | 2 | throwChecksumError(); |
7941 | 36 | } |
7942 | | |
7943 | | |
7944 | | /************************************************************************* |
7945 | | // |
7946 | | **************************************************************************/ |
7947 | | |
7948 | 89.1k | PackLinuxElf32x86::PackLinuxElf32x86(InputFile *f) : super(f) |
7949 | 89.1k | { |
7950 | 89.1k | e_machine = Elf32_Ehdr::EM_386; |
7951 | 89.1k | ei_class = Elf32_Ehdr::ELFCLASS32; |
7952 | 89.1k | ei_data = Elf32_Ehdr::ELFDATA2LSB; |
7953 | 89.1k | ei_osabi = Elf32_Ehdr::ELFOSABI_LINUX; |
7954 | 89.1k | } |
7955 | | |
7956 | | PackLinuxElf32x86::~PackLinuxElf32x86() |
7957 | 88.1k | { |
7958 | 88.1k | } |
7959 | | |
7960 | | tribool PackLinuxElf32x86::canUnpack() // bool, except -1: format known, but not packed |
7961 | 88.1k | { |
7962 | 88.1k | if (super::canUnpack()) { |
7963 | 365 | return true; |
7964 | 365 | } |
7965 | 87.8k | return false; |
7966 | 88.1k | } |
7967 | | |
7968 | | Linker* PackLinuxElf32x86::newLinker() const |
7969 | 0 | { |
7970 | 0 | return new ElfLinkerX86; |
7971 | 0 | } |
7972 | | |
7973 | 45.1k | PackBSDElf32x86::PackBSDElf32x86(InputFile *f) : super(f) |
7974 | 45.1k | { |
7975 | 45.1k | e_machine = Elf32_Ehdr::EM_386; |
7976 | 45.1k | ei_class = Elf32_Ehdr::ELFCLASS32; |
7977 | 45.1k | ei_data = Elf32_Ehdr::ELFDATA2LSB; |
7978 | 45.1k | } |
7979 | | |
7980 | | PackBSDElf32x86::~PackBSDElf32x86() |
7981 | | { |
7982 | | } |
7983 | | |
7984 | 23.0k | PackFreeBSDElf32x86::PackFreeBSDElf32x86(InputFile *f) : super(f) |
7985 | 23.0k | { |
7986 | 23.0k | ei_osabi = Elf32_Ehdr::ELFOSABI_FREEBSD; |
7987 | 23.0k | } |
7988 | | |
7989 | | PackFreeBSDElf32x86::~PackFreeBSDElf32x86() |
7990 | | { |
7991 | | } |
7992 | | |
7993 | 22.0k | PackNetBSDElf32x86::PackNetBSDElf32x86(InputFile *f) : super(f) |
7994 | 22.0k | { |
7995 | 22.0k | ei_osabi = Elf32_Ehdr::ELFOSABI_NETBSD; |
7996 | 22.0k | osabi_note = "NetBSD"; |
7997 | 22.0k | } |
7998 | | |
7999 | | PackNetBSDElf32x86::~PackNetBSDElf32x86() |
8000 | | { |
8001 | | } |
8002 | | |
8003 | 22.0k | PackOpenBSDElf32x86::PackOpenBSDElf32x86(InputFile *f) : super(f) |
8004 | 22.0k | { |
8005 | 22.0k | ei_osabi = Elf32_Ehdr::ELFOSABI_OPENBSD; |
8006 | 22.0k | osabi_note = "OpenBSD"; |
8007 | 22.0k | } |
8008 | | |
8009 | | PackOpenBSDElf32x86::~PackOpenBSDElf32x86() |
8010 | | { |
8011 | | } |
8012 | | |
8013 | | int const * |
8014 | | PackLinuxElf32x86::getFilters() const |
8015 | 0 | { |
8016 | 0 | static const int filters[] = { |
8017 | | // 0x49 is 5-byte CALL or JMP, and 6-byte Jxx |
8018 | | // 0x46 is 5-byte CALL or JMP |
8019 | 0 | 0x49, 0x46, |
8020 | | // FIXME 2002-11-11: We use stub/fold_elf86.asm, which calls the |
8021 | | // decompressor multiple times, and unfilter is independent of decompress. |
8022 | | // Currently only filters 0x49, 0x46, 0x80..0x87 can handle this; |
8023 | | // and 0x80..0x87 are regarded as "untested". |
8024 | | #if 0 |
8025 | | 0x26, 0x24, 0x11, 0x14, 0x13, 0x16, 0x25, 0x15, 0x12, |
8026 | | #endif |
8027 | | #if 0 |
8028 | | 0x83, 0x36, 0x26, |
8029 | | 0x86, 0x80, |
8030 | | 0x84, 0x87, 0x81, |
8031 | | 0x82, 0x85, |
8032 | | 0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12, |
8033 | | #endif |
8034 | 0 | FT_END }; |
8035 | 0 | return filters; |
8036 | 0 | } |
8037 | | |
8038 | 18.8k | PackLinuxElf32armLe::PackLinuxElf32armLe(InputFile *f) : super(f) |
8039 | 18.8k | { |
8040 | 18.8k | e_machine = Elf32_Ehdr::EM_ARM; |
8041 | 18.8k | ei_class = Elf32_Ehdr::ELFCLASS32; |
8042 | 18.8k | ei_data = Elf32_Ehdr::ELFDATA2LSB; |
8043 | 18.8k | ei_osabi = Elf32_Ehdr::ELFOSABI_ARM; |
8044 | 18.8k | } |
8045 | | |
8046 | | PackLinuxElf32armLe::~PackLinuxElf32armLe() |
8047 | 18.8k | { |
8048 | 18.8k | } |
8049 | | |
8050 | 14.3k | PackLinuxElf32mipseb::PackLinuxElf32mipseb(InputFile *f) : super(f) |
8051 | 14.3k | { |
8052 | 14.3k | e_machine = Elf32_Ehdr::EM_MIPS; |
8053 | 14.3k | ei_class = Elf32_Ehdr::ELFCLASS32; |
8054 | 14.3k | ei_data = Elf32_Ehdr::ELFDATA2MSB; |
8055 | 14.3k | ei_osabi = Elf32_Ehdr::ELFOSABI_LINUX; |
8056 | 14.3k | } |
8057 | | |
8058 | | PackLinuxElf32mipseb::~PackLinuxElf32mipseb() |
8059 | 14.3k | { |
8060 | 14.3k | } |
8061 | | |
8062 | 14.4k | PackLinuxElf32mipsel::PackLinuxElf32mipsel(InputFile *f) : super(f) |
8063 | 14.4k | { |
8064 | 14.4k | e_machine = Elf32_Ehdr::EM_MIPS; |
8065 | 14.4k | ei_class = Elf32_Ehdr::ELFCLASS32; |
8066 | 14.4k | ei_data = Elf32_Ehdr::ELFDATA2LSB; |
8067 | 14.4k | ei_osabi = Elf32_Ehdr::ELFOSABI_LINUX; |
8068 | 14.4k | } |
8069 | | |
8070 | | PackLinuxElf32mipsel::~PackLinuxElf32mipsel() |
8071 | 14.4k | { |
8072 | 14.4k | } |
8073 | | |
8074 | | Linker* PackLinuxElf32armLe::newLinker() const |
8075 | 0 | { |
8076 | 0 | return new ElfLinkerArmLE(); |
8077 | 0 | } |
8078 | | |
8079 | | Linker* PackLinuxElf32mipseb::newLinker() const |
8080 | 0 | { |
8081 | 0 | return new ElfLinkerMipsBE(); |
8082 | 0 | } |
8083 | | |
8084 | | Linker* PackLinuxElf32mipsel::newLinker() const |
8085 | 0 | { |
8086 | 0 | return new ElfLinkerMipsLE(); |
8087 | 0 | } |
8088 | | |
8089 | 18.8k | PackLinuxElf32armBe::PackLinuxElf32armBe(InputFile *f) : super(f) |
8090 | 18.8k | { |
8091 | 18.8k | e_machine = Elf32_Ehdr::EM_ARM; |
8092 | 18.8k | ei_class = Elf32_Ehdr::ELFCLASS32; |
8093 | 18.8k | ei_data = Elf32_Ehdr::ELFDATA2MSB; |
8094 | 18.8k | ei_osabi = Elf32_Ehdr::ELFOSABI_ARM; |
8095 | 18.8k | } |
8096 | | |
8097 | | PackLinuxElf32armBe::~PackLinuxElf32armBe() |
8098 | 16.8k | { |
8099 | 16.8k | } |
8100 | | |
8101 | | Linker* PackLinuxElf32armBe::newLinker() const |
8102 | 0 | { |
8103 | 0 | return new ElfLinkerArmBE(); |
8104 | 0 | } |
8105 | | |
8106 | | unsigned |
8107 | | PackLinuxElf32::elf_get_offset_from_address(unsigned addr) const |
8108 | 19.4k | { |
8109 | 19.4k | return elf_get_offset_from_Phdrs(addr, phdri); |
8110 | 19.4k | } |
8111 | | |
8112 | | unsigned |
8113 | | PackLinuxElf32::elf_get_offset_from_Phdrs(unsigned addr, Elf32_Phdr const *phdr0) const |
8114 | 19.4k | { |
8115 | 19.4k | Elf32_Phdr const *phdr = phdr0; |
8116 | 19.4k | int j = e_phnum; |
8117 | 52.5k | for (; --j>=0; ++phdr) if (is_LOAD(phdr)) { |
8118 | 22.4k | unsigned const t = addr - get_te32(&phdr->p_vaddr); |
8119 | 22.4k | if (t < get_te32(&phdr->p_filesz)) { |
8120 | 19.3k | unsigned const p_offset = get_te32(&phdr->p_offset); |
8121 | 19.3k | if (file_size_u <= p_offset) { // FIXME: weak |
8122 | 11 | char msg[40]; snprintf(msg, sizeof(msg), |
8123 | 11 | "bad Elf32_Phdr[%d].p_offset %x", |
8124 | 11 | -1+ e_phnum - j, p_offset); |
8125 | 11 | throwCantPack(msg); |
8126 | 11 | } |
8127 | 19.2k | return t + p_offset; |
8128 | 19.3k | } |
8129 | 22.4k | } |
8130 | 147 | return 0; |
8131 | 19.4k | } |
8132 | | |
8133 | | u32_t // returns .p_offset |
8134 | | PackLinuxElf32::check_pt_load(Elf32_Phdr const *const phdr) |
8135 | 6.59k | { |
8136 | 6.59k | u32_t filesz = get_te32(&phdr->p_filesz); |
8137 | 6.59k | u32_t offset = get_te32(&phdr->p_offset), offend = filesz + offset; |
8138 | 6.59k | u32_t vaddr = get_te32(&phdr->p_vaddr); |
8139 | 6.59k | u32_t paddr = get_te32(&phdr->p_paddr); |
8140 | 6.59k | u32_t align = get_te32(&phdr->p_align); |
8141 | | |
8142 | 6.59k | if ((-1+ align) & (paddr ^ vaddr) |
8143 | 6.51k | || file_size_u32 <= (u32_t)offset |
8144 | 6.46k | || file_size_u32 < (u32_t)offend |
8145 | 6.38k | || file_size_u32 < (u32_t)filesz) { |
8146 | 254 | char msg[50]; snprintf(msg, sizeof(msg), "bad PT_LOAD phdr[%u]", |
8147 | 254 | (unsigned)(phdr - phdri)); |
8148 | 254 | throwCantPack(msg); |
8149 | 254 | } |
8150 | 6.34k | return offset; |
8151 | 6.59k | } |
8152 | | |
8153 | | Elf32_Dyn const * |
8154 | | PackLinuxElf32::elf_has_dynamic(unsigned int key) const |
8155 | 0 | { |
8156 | 0 | Elf32_Dyn const *dynp= dynseg; |
8157 | 0 | if (dynp) |
8158 | 0 | for (; Elf32_Dyn::DT_NULL!=dynp->d_tag; ++dynp) if (get_te32(&dynp->d_tag)==key) { |
8159 | 0 | return dynp; |
8160 | 0 | } |
8161 | 0 | return nullptr; |
8162 | 0 | } |
8163 | | |
8164 | | unsigned // checked .p_offset; sz_dynseg set |
8165 | | PackLinuxElf32::check_pt_dynamic(Elf32_Phdr const *const phdr) |
8166 | 4.22k | { |
8167 | 4.22k | unsigned t = get_te32(&phdr->p_offset), s = sizeof(Elf32_Dyn) + t; |
8168 | 4.22k | unsigned vaddr = get_te32(&phdr->p_vaddr); |
8169 | 4.22k | unsigned filesz = get_te32(&phdr->p_filesz), memsz = get_te32(&phdr->p_memsz); |
8170 | 4.22k | unsigned align = get_te32(&phdr->p_align); |
8171 | 4.22k | if (file_size_u < t || s < t |
8172 | 4.18k | || file_size_u < filesz |
8173 | 4.14k | || file_size_u < (filesz + t) |
8174 | 4.13k | || t < (e_phnum*sizeof(Elf32_Phdr) + sizeof(Elf32_Ehdr)) |
8175 | 4.07k | || (3 & t) || (7 & (filesz | memsz)) // .balign 4; 8==sizeof(Elf32_Dyn) |
8176 | 4.06k | || (-1+ align) & (t ^ vaddr) |
8177 | 4.03k | || file_size_u <= memsz |
8178 | 3.99k | || filesz < sizeof(Elf32_Dyn) |
8179 | 3.98k | || memsz < sizeof(Elf32_Dyn) |
8180 | 3.98k | || filesz < memsz) { |
8181 | 260 | char msg[50]; snprintf(msg, sizeof(msg), "bad PT_DYNAMIC phdr[%u]", |
8182 | 260 | (unsigned)(phdr - phdri)); |
8183 | 260 | throwCantPack(msg); |
8184 | 260 | } |
8185 | 3.96k | sz_dynseg = memsz; |
8186 | 3.96k | return t; |
8187 | 4.22k | } |
8188 | | |
8189 | | Elf32_Dyn *PackLinuxElf32::elf_find_dynptr(unsigned int key) const |
8190 | 36.2k | { |
8191 | 36.2k | Elf32_Dyn *dynp= dynseg; |
8192 | 36.2k | if (dynp) { |
8193 | 31.2k | Elf32_Dyn *const last = (Elf32_Dyn *)(sz_dynseg + (char *)dynseg); |
8194 | 581k | for (; dynp < last; ++dynp) { |
8195 | 578k | if (get_te32(&dynp->d_tag)==key) { |
8196 | 18.0k | return dynp; |
8197 | 18.0k | } |
8198 | 560k | if (Elf32_Dyn::DT_NULL == dynp->d_tag) { |
8199 | 10.9k | return nullptr; |
8200 | 10.9k | } |
8201 | 560k | } |
8202 | 31.2k | } |
8203 | 7.31k | return nullptr; |
8204 | 36.2k | } |
8205 | | |
8206 | | Elf64_Dyn *PackLinuxElf64::elf_find_dynptr(unsigned int key) const |
8207 | 24.7k | { |
8208 | 24.7k | Elf64_Dyn *dynp= dynseg; |
8209 | 24.7k | if (dynp) { |
8210 | 21.9k | Elf64_Dyn *const last = (Elf64_Dyn *)(sz_dynseg + (char *)dynseg); |
8211 | 200k | for (; dynp < last; ++dynp) { |
8212 | 198k | if (get_te64(&dynp->d_tag)==key) { |
8213 | 10.8k | return dynp; |
8214 | 10.8k | } |
8215 | 187k | if (Elf64_Dyn::DT_NULL == dynp->d_tag) { |
8216 | 8.92k | return nullptr; |
8217 | 8.92k | } |
8218 | 187k | } |
8219 | 21.9k | } |
8220 | 4.96k | return nullptr; |
8221 | 24.7k | } |
8222 | | |
8223 | | void * |
8224 | | PackLinuxElf32::elf_find_dynamic(unsigned int key) const |
8225 | 18.6k | { |
8226 | 18.6k | Elf32_Dyn const *dynp= elf_find_dynptr(key); |
8227 | 18.6k | if (dynp) { |
8228 | 11.9k | unsigned const t= elf_get_offset_from_address(get_te32(&dynp->d_val)); |
8229 | 11.9k | if (t && t < file_size_u) { |
8230 | 11.6k | return t + file_image; |
8231 | 11.6k | } |
8232 | 11.9k | } |
8233 | 7.07k | return nullptr; |
8234 | 18.6k | } |
8235 | | |
8236 | | void * |
8237 | | PackLinuxElf64::elf_find_dynamic(unsigned int key) const |
8238 | 10.7k | { |
8239 | 10.7k | Elf64_Dyn const *dynp= elf_find_dynptr(key); |
8240 | 10.7k | if (dynp) { |
8241 | 6.87k | upx_uint64_t const t= elf_get_offset_from_address(get_te64(&dynp->d_val)); |
8242 | 6.87k | if (t && t < file_size_u) { |
8243 | 6.61k | return t + file_image; |
8244 | 6.61k | } |
8245 | 6.87k | } |
8246 | 4.16k | return nullptr; |
8247 | 10.7k | } |
8248 | | |
8249 | | upx_uint64_t |
8250 | | PackLinuxElf64::elf_unsigned_dynamic(unsigned int key) const |
8251 | 13.9k | { |
8252 | 13.9k | Elf64_Dyn const *dynp= elf_find_dynptr(key); |
8253 | 13.9k | if (dynp) { |
8254 | 3.93k | return get_te64(&dynp->d_val); |
8255 | 3.93k | } |
8256 | 9.98k | return 0; |
8257 | 13.9k | } |
8258 | | |
8259 | | upx_uint64_t |
8260 | | PackLinuxElf32::elf_unsigned_dynamic(unsigned int key) const |
8261 | 17.5k | { |
8262 | 17.5k | Elf32_Dyn const *dynp= elf_find_dynptr(key); |
8263 | 17.5k | if (dynp) { |
8264 | 6.10k | return get_te32(&dynp->d_val); |
8265 | 6.10k | } |
8266 | 11.4k | return 0; |
8267 | 17.5k | } |
8268 | | |
8269 | | upx_uint64_t |
8270 | | PackLinuxElf64::elf_get_offset_from_address(upx_uint64_t addr) const |
8271 | 12.4k | { |
8272 | 12.4k | Elf64_Phdr const *phdr = phdri; |
8273 | 12.4k | int j = e_phnum; |
8274 | 46.8k | for (; --j>=0; ++phdr) if (is_LOAD(phdr)) { |
8275 | 15.5k | upx_uint64_t const t = addr - get_te64(&phdr->p_vaddr); |
8276 | 15.5k | if (t < get_te64(&phdr->p_filesz)) { |
8277 | 12.3k | upx_uint64_t const p_offset = get_te64(&phdr->p_offset); |
8278 | 12.3k | if (file_size_u <= p_offset) { // FIXME: weak |
8279 | 135 | char msg[40]; snprintf(msg, sizeof(msg), |
8280 | 135 | "bad Elf64_Phdr[%d].p_offset %#lx", |
8281 | 135 | -1+ e_phnum - j, (long unsigned)p_offset); |
8282 | 135 | throwCantPack(msg); |
8283 | 135 | } |
8284 | 12.2k | return t + p_offset; |
8285 | 12.3k | } |
8286 | 15.5k | } |
8287 | 87 | return 0; |
8288 | 12.4k | } |
8289 | | |
8290 | | u64_t // returns .p_offset |
8291 | | PackLinuxElf64::check_pt_load(Elf64_Phdr const *const phdr) |
8292 | 4.85k | { |
8293 | 4.85k | u64_t filesz = get_te64(&phdr->p_filesz); |
8294 | 4.85k | u64_t offset = get_te64(&phdr->p_offset), offend = filesz + offset; |
8295 | 4.85k | u64_t vaddr = get_te64(&phdr->p_vaddr); |
8296 | 4.85k | u64_t paddr = get_te64(&phdr->p_paddr); |
8297 | 4.85k | u64_t align = get_te64(&phdr->p_align); |
8298 | | |
8299 | 4.85k | if ((-1+ align) & (paddr ^ vaddr) |
8300 | 4.58k | || file_size_u <= (u64_t)offset |
8301 | 4.38k | || file_size_u < (u64_t)offend |
8302 | 4.24k | || file_size_u < (u64_t)filesz) { |
8303 | 663 | char msg[50]; snprintf(msg, sizeof(msg), "bad PT_LOAD phdr[%u]", |
8304 | 663 | (unsigned)(phdr - phdri)); |
8305 | 663 | throwCantPack(msg); |
8306 | 663 | } |
8307 | 4.18k | return offset; |
8308 | 4.85k | } |
8309 | | |
8310 | | Elf64_Dyn const * |
8311 | | PackLinuxElf64::elf_has_dynamic(unsigned int key) const |
8312 | 0 | { |
8313 | 0 | Elf64_Dyn const *dynp= dynseg; |
8314 | 0 | if (dynp) |
8315 | 0 | for (; Elf64_Dyn::DT_NULL!=dynp->d_tag; ++dynp) if (get_te64(&dynp->d_tag)==key) { |
8316 | 0 | return dynp; |
8317 | 0 | } |
8318 | 0 | return nullptr; |
8319 | 0 | } |
8320 | | |
8321 | | upx_uint64_t // checked .p_offset; sz_dynseg set |
8322 | | PackLinuxElf64::check_pt_dynamic(Elf64_Phdr const *const phdr) |
8323 | 4.17k | { |
8324 | 4.17k | upx_uint64_t t = get_te64(&phdr->p_offset), s = sizeof(Elf64_Dyn) + t; |
8325 | 4.17k | upx_uint64_t vaddr = get_te64(&phdr->p_vaddr); |
8326 | 4.17k | upx_uint64_t filesz = get_te64(&phdr->p_filesz), memsz = get_te64(&phdr->p_memsz); |
8327 | 4.17k | upx_uint64_t align = get_te64(&phdr->p_align); |
8328 | 4.17k | if (file_size_u < t || s < t |
8329 | 4.06k | || file_size_u < filesz |
8330 | 3.88k | || file_size_u < (filesz + t) |
8331 | 3.87k | || t < (e_phnum*sizeof(Elf64_Phdr) + sizeof(Elf64_Ehdr)) |
8332 | 3.85k | || (7 & t) || (0xf & (filesz | memsz)) // .balign 8; 16==sizeof(Elf64_Dyn) |
8333 | 3.82k | || (-1+ align) & (t ^ vaddr) |
8334 | 3.71k | || file_size_u <= memsz |
8335 | 3.53k | || filesz < sizeof(Elf64_Dyn) |
8336 | 3.53k | || memsz < sizeof(Elf64_Dyn) |
8337 | 3.53k | || filesz < memsz) { |
8338 | 659 | char msg[50]; snprintf(msg, sizeof(msg), "bad PT_DYNAMIC phdr[%u]", |
8339 | 659 | (unsigned)(phdr - phdri)); |
8340 | 659 | throwCantPack(msg); |
8341 | 659 | } |
8342 | 3.52k | sz_dynseg = memsz; |
8343 | 3.52k | return t; |
8344 | 4.17k | } |
8345 | | |
8346 | | void |
8347 | | PackLinuxElf64::sort_DT64_offsets(Elf64_Dyn const *const dynp0) |
8348 | 2.83k | { |
8349 | 2.83k | mb_dt_offsets.alloc(sizeof(unsigned) * sizeof(dt_keys)/sizeof(dt_keys[0])); |
8350 | 2.83k | mb_dt_offsets.clear(); |
8351 | 2.83k | dt_offsets = (unsigned *)mb_dt_offsets.getVoidPtr(); |
8352 | 2.83k | unsigned n_off = 0, k; |
8353 | 34.0k | for (unsigned j=0; ((k = dt_keys[j]), k); ++j) { |
8354 | 31.5k | dt_offsets[n_off] = 0; // default to "not found" |
8355 | 31.5k | u64_t rva = 0; |
8356 | 31.5k | if (k < DT_NUM) { // in range of easy table |
8357 | 20.7k | if (!dt_table[k]) { |
8358 | 12.9k | continue; |
8359 | 12.9k | } |
8360 | 7.81k | rva = get_te64(&dynp0[-1+ dt_table[k]].d_val); |
8361 | 7.81k | } |
8362 | 10.7k | else if (file_image) { // why is this guard necessary? |
8363 | 10.7k | rva = elf_unsigned_dynamic(k); // zero if not found |
8364 | 10.7k | } |
8365 | 18.5k | if (!rva) { // not present in input |
8366 | 9.28k | continue; |
8367 | 9.28k | } |
8368 | 9.31k | Elf64_Phdr const *const phdr = elf_find_Phdr_for_va(rva, phdri, e_phnum); |
8369 | 9.31k | if (!phdr) { |
8370 | 301 | char msg[60]; snprintf(msg, sizeof(msg), "bad DT_{%#x} = %#llx (no Phdr)", |
8371 | 301 | k, rva); |
8372 | 301 | throwCantPack(msg); |
8373 | 301 | } |
8374 | 9.01k | dt_offsets[n_off] = (rva - get_te64(&phdr->p_vaddr)) + get_te64(&phdr->p_offset); |
8375 | | |
8376 | 9.01k | if (file_size <= dt_offsets[n_off]) { |
8377 | 56 | char msg[60]; snprintf(msg, sizeof(msg), "bad DT_{%#x} = %#x (beyond EOF)", |
8378 | 56 | k, dt_offsets[n_off]); |
8379 | 56 | throwCantPack(msg); |
8380 | 56 | } |
8381 | 8.95k | n_off += !!dt_offsets[n_off]; |
8382 | 8.95k | } |
8383 | 2.47k | dt_offsets[n_off++] = file_size; // sentinel |
8384 | 2.47k | upx_qsort(dt_offsets, n_off, sizeof(dt_offsets[0]), qcmp_unsigned); |
8385 | 2.47k | } |
8386 | | |
8387 | | unsigned PackLinuxElf64::find_dt_ndx(u64_t rva) |
8388 | 4.11k | { |
8389 | 4.11k | unsigned *const dto = (unsigned *)mb_dt_offsets.getVoidPtr(); |
8390 | 4.11k | unsigned const dto_size = mb_dt_offsets.getSize() / sizeof(*dto); |
8391 | 9.84k | for (unsigned j = 0; j < dto_size && dto[j]; ++j) { // linear search of short table |
8392 | 9.65k | if (rva == dto[j]) { |
8393 | 3.93k | return j; |
8394 | 3.93k | } |
8395 | 9.65k | } |
8396 | 183 | return ~0u; |
8397 | 4.11k | } |
8398 | | |
8399 | | unsigned PackLinuxElf64::elf_find_table_size(unsigned dt_type, unsigned sh_type) |
8400 | 4.45k | { |
8401 | 4.45k | Elf64_Shdr const *sec = elf_find_section_type(sh_type); |
8402 | 4.45k | if (sec) { // Cheat the easy way: use _Shdr. (No _Shdr anyway for de-compression) |
8403 | 0 | return get_te64(&sec->sh_size); |
8404 | 0 | } |
8405 | | // Honest hard work: use _Phdr |
8406 | 4.45k | unsigned x_rva; |
8407 | 4.45k | if (dt_type < DT_NUM) { |
8408 | 3.33k | unsigned const x_ndx = dt_table[dt_type]; |
8409 | 3.33k | if (!x_ndx) { // no such entry |
8410 | 333 | return 0; |
8411 | 333 | } |
8412 | 3.00k | x_rva = get_te64(&dynseg[-1+ x_ndx].d_val); |
8413 | 3.00k | } |
8414 | 1.12k | else { |
8415 | 1.12k | x_rva = elf_unsigned_dynamic(dt_type); |
8416 | 1.12k | } |
8417 | 4.12k | Elf64_Phdr const *const x_phdr = elf_find_Phdr_for_va(x_rva, phdri, e_phnum); |
8418 | 4.12k | if (!x_phdr) |
8419 | 12 | return ~0u; // corrupted Phdrs? |
8420 | 4.11k | unsigned const d_off = x_rva - get_te64(&x_phdr->p_vaddr); |
8421 | 4.11k | unsigned const y_ndx = find_dt_ndx(d_off + get_te64(&x_phdr->p_offset)); |
8422 | 4.11k | if (~0u != y_ndx) { |
8423 | 3.93k | return dt_offsets[1+ y_ndx] - dt_offsets[y_ndx]; |
8424 | 3.93k | } |
8425 | 183 | return ~0u; |
8426 | 4.11k | } |
8427 | | |
8428 | | void |
8429 | | PackLinuxElf64::invert_pt_dynamic(Elf64_Dyn const *dynp, upx_uint64_t headway) |
8430 | 3.52k | { |
8431 | 3.52k | if (dt_table[Elf64_Dyn::DT_NULL]) { |
8432 | 356 | return; // not 1st time; do not change upx_dt_init |
8433 | 356 | } |
8434 | 3.16k | Elf64_Dyn const *const dynp0 = dynp; |
8435 | 3.16k | unsigned ndx = 0; |
8436 | 3.16k | unsigned const limit = headway / sizeof(*dynp); |
8437 | 3.16k | if (dynp) |
8438 | 36.4k | for (; ; ++ndx, ++dynp) { |
8439 | 36.4k | if (limit <= ndx) { |
8440 | 11 | throwCantPack("DT_NULL not found"); |
8441 | 11 | } |
8442 | 36.4k | upx_uint64_t const d_tag = get_te64(&dynp->d_tag); |
8443 | 36.4k | if (d_tag>>32) { // outrageous |
8444 | 217 | throwCantPack("bad Elf64_Dyn[%d].d_tag %#lx", |
8445 | 217 | ndx, (long unsigned)d_tag); |
8446 | 217 | } |
8447 | 36.2k | if (d_tag < DT_NUM) { |
8448 | 24.0k | if (Elf64_Dyn::DT_NEEDED != d_tag |
8449 | 22.3k | && dt_table[d_tag] |
8450 | 311 | && get_te64(&dynp->d_val) |
8451 | 311 | != get_te64(&dynp0[-1+ dt_table[d_tag]].d_val)) { |
8452 | 103 | throwCantPack("duplicate DT_%#x: [%#x] [%#x]", |
8453 | 103 | (unsigned)d_tag, -1+ dt_table[d_tag], ndx); |
8454 | 103 | } |
8455 | 23.9k | dt_table[d_tag] = 1+ ndx; |
8456 | 23.9k | } |
8457 | 36.1k | if (Elf64_Dyn::DT_NULL == d_tag) { |
8458 | 2.83k | break; // check here so that dt_table[DT_NULL] is set |
8459 | 2.83k | } |
8460 | 36.1k | } |
8461 | 2.83k | sort_DT64_offsets(dynp0); |
8462 | | |
8463 | 2.83k | upx_dt_init = 0; |
8464 | 2.83k | if (dt_table[Elf64_Dyn::DT_INIT]) upx_dt_init = Elf64_Dyn::DT_INIT; |
8465 | 2.30k | else if (dt_table[Elf64_Dyn::DT_PREINIT_ARRAY]) upx_dt_init = Elf64_Dyn::DT_PREINIT_ARRAY; |
8466 | 2.05k | else if (dt_table[Elf64_Dyn::DT_INIT_ARRAY]) upx_dt_init = Elf64_Dyn::DT_INIT_ARRAY; |
8467 | | |
8468 | 2.83k | unsigned const z_str = dt_table[Elf64_Dyn::DT_STRSZ]; |
8469 | 2.83k | strtab_max = !z_str ? 0 : get_te64(&dynp0[-1+ z_str].d_val); |
8470 | 2.83k | unsigned const z_tab = dt_table[Elf64_Dyn::DT_STRTAB]; |
8471 | 2.83k | unsigned const tmp1 = !z_tab ? 0 : get_te64(&dynp0[-1+ z_tab].d_val); |
8472 | 2.83k | if (tmp1 < sz_elf_hdrs) { |
8473 | 85 | throwCantPack("bad DT_STRTAB %#x", tmp1); |
8474 | 85 | } |
8475 | 2.75k | unsigned const strtab_beg = !z_tab ? 0 : elf_get_offset_from_address(tmp1); |
8476 | | |
8477 | 2.75k | if (!z_str || !z_tab || !(strtab_max + strtab_beg) |
8478 | 2.22k | || (this->file_size - strtab_beg) < strtab_max // strtab overlaps EOF |
8479 | | // last string in table must have terminating NUL |
8480 | 2.16k | || '\0' != ((char *)file_image.getVoidPtr())[-1+ strtab_max + strtab_beg] |
8481 | 2.75k | ) { |
8482 | 105 | throwCantPack("bad DT_STRSZ %#x", strtab_max); |
8483 | 105 | } |
8484 | | |
8485 | 2.64k | { // Find end of DT_SYMTAB |
8486 | 2.64k | unsigned const tmp2 = elf_find_table_size(Elf64_Dyn::DT_SYMTAB, |
8487 | 2.64k | Elf64_Shdr::SHT_DYNSYM); |
8488 | 2.64k | symnum_max = (~0u == tmp2) ? 0 : tmp2 / sizeof(Elf64_Sym); |
8489 | 2.64k | } |
8490 | | |
8491 | 2.64k | unsigned v_sym = dt_table[Elf64_Dyn::DT_SYMTAB]; |
8492 | 2.64k | if (v_sym) { |
8493 | 1.82k | v_sym = elf_get_offset_from_address(get_te64(&dynp0[-1+ v_sym].d_val)); |
8494 | 1.82k | } |
8495 | | |
8496 | 2.64k | unsigned v_hsh = dt_table[Elf64_Dyn::DT_HASH]; |
8497 | 2.64k | if (v_hsh) { |
8498 | 1.34k | v_hsh = elf_get_offset_from_address(get_te64(&dynp0[-1+ v_hsh].d_val)); |
8499 | 1.34k | } |
8500 | 2.64k | if (v_hsh && file_image) { |
8501 | 1.31k | hashtab = (unsigned const *)elf_find_dynamic(Elf64_Dyn::DT_HASH); |
8502 | 1.31k | if (!hashtab) { |
8503 | 133 | throwCantPack("bad DT_HASH %#x", v_hsh); |
8504 | 133 | } |
8505 | | // Find end of DT_HASH |
8506 | 1.18k | hashend = (unsigned const *)(void const *)(elf_find_table_size( |
8507 | 1.18k | Elf64_Dyn::DT_HASH, Elf64_Shdr::SHT_HASH) + (char const *)hashtab); |
8508 | 1.18k | if (!hashtab || (char const *)hashend <= (char const *)&hashtab[2] |
8509 | 1.17k | || file_image.getSizeInBytes() |
8510 | 1.17k | < (unsigned)((char const *)&hashtab[2] - (char *)&file_image[0]) ) |
8511 | 8 | { |
8512 | 8 | throwCantPack("bad DT_HASH %#x", v_hsh); |
8513 | 8 | } |
8514 | | |
8515 | 1.17k | unsigned const nbucket = get_te32(&hashtab[0]); |
8516 | 1.17k | unsigned const *const buckets = &hashtab[2]; |
8517 | 1.17k | unsigned const *const chains = &buckets[nbucket]; (void)chains; |
8518 | 1.17k | if ((unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image)) |
8519 | 1.17k | <= sizeof(unsigned)*nbucket ) { |
8520 | 57 | throwCantPack("bad nbucket %#x\n", nbucket); |
8521 | 57 | } |
8522 | | |
8523 | 1.11k | if ((unsigned)(hashend - buckets) < nbucket |
8524 | 1.10k | || !v_sym || file_size_u <= v_sym |
8525 | 1.09k | || ((v_hsh < v_sym) && (v_sym - v_hsh) < sizeof(*buckets)*(2+ nbucket)) |
8526 | 1.11k | ) { |
8527 | 47 | throwCantPack("bad DT_HASH nbucket=%#x len=%#x", |
8528 | 47 | nbucket, (v_sym - v_hsh)); |
8529 | 47 | } |
8530 | 1.06k | unsigned chmax = 0; |
8531 | 221k | for (unsigned j= 0; j < nbucket; ++j) { |
8532 | 220k | unsigned x = get_te32(&buckets[j]); |
8533 | 220k | if (chmax < x) { |
8534 | 2.71k | chmax = x; |
8535 | 2.71k | } |
8536 | 220k | } |
8537 | 1.06k | if ((v_hsh < v_sym) && (v_sym - v_hsh) < |
8538 | 783 | (sizeof(*buckets)*(2+ nbucket) + sizeof(*chains)*(1+ chmax))) { |
8539 | 80 | throwCantPack("bad DT_HASH nbucket=%#x len=%#x", |
8540 | 80 | nbucket, (v_sym - v_hsh)); |
8541 | 80 | } |
8542 | 1.06k | } |
8543 | 2.32k | unsigned const v_gsh = elf_unsigned_dynamic(Elf64_Dyn::DT_GNU_HASH); |
8544 | 2.32k | if (v_gsh && file_image) { |
8545 | | // Not similar to DT_HASH because DT_GNU_HASH is not small (0x6ffffef5). |
8546 | 1.12k | gashtab = (unsigned const *)elf_find_dynamic(Elf64_Dyn::DT_GNU_HASH); |
8547 | 1.12k | gashend = (unsigned const *)(void const *)(elf_find_table_size( |
8548 | 1.12k | Elf64_Dyn::DT_GNU_HASH, Elf64_Shdr::SHT_GNU_HASH) + (char const *)gashtab); |
8549 | 1.12k | if (!gashtab || (char const *)gashend <= (char const *)&gashtab[4] |
8550 | 1.07k | || file_image.getSizeInBytes() |
8551 | 1.07k | < (unsigned)((char const *)&gashtab[4] - (char *)&file_image[0]) ) |
8552 | 55 | { |
8553 | 55 | throwCantPack("bad DT_GNU_HASH %#x", v_gsh); |
8554 | 55 | } |
8555 | | |
8556 | 1.07k | unsigned const n_bucket = get_te32(&gashtab[0]); |
8557 | 1.07k | unsigned const symbias = get_te32(&gashtab[1]); |
8558 | 1.07k | unsigned const n_bitmask = get_te32(&gashtab[2]); |
8559 | 1.07k | unsigned const gnu_shift = get_te32(&gashtab[3]); |
8560 | 1.07k | upx_uint64_t const *const bitmask = (upx_uint64_t const *)(void const *)&gashtab[4]; |
8561 | 1.07k | unsigned const *const buckets = (unsigned const *)&bitmask[n_bitmask]; |
8562 | 1.07k | unsigned const *const hasharr = &buckets[n_bucket]; (void)hasharr; |
8563 | 1.07k | if (!n_bucket || (1u<<31) <= n_bucket /* fie on fuzzers */ |
8564 | 986 | || (unsigned)(gashend - buckets) < n_bucket |
8565 | 957 | || (file_size + file_image) <= (void const *)hasharr) { |
8566 | 160 | throwCantPack("bad n_bucket %#x\n", n_bucket); |
8567 | 160 | } |
8568 | | // It would be better to detect zeroes shifted into low 6 bits of: |
8569 | | // (077 & (hash_32 >> gnu_shift)) |
8570 | | // but compilers can be stupid. |
8571 | 910 | if (31 < gnu_shift) { |
8572 | 34 | throwCantPack("bad gnu_shift %#x", gnu_shift); |
8573 | 34 | } |
8574 | | // unsigned const *const gashend = &hasharr[n_bucket]; |
8575 | | // minimum, except: |
8576 | | // Rust and Android trim unused zeroes from high end of hasharr[] |
8577 | 876 | unsigned bmax = 0; |
8578 | 112k | for (unsigned j= 0; j < n_bucket; ++j) { |
8579 | 112k | unsigned bj = get_te32(&buckets[j]); |
8580 | 112k | if (bj) { |
8581 | 87.7k | if (bj < symbias) { |
8582 | 13 | throwCantPack("bad DT_GNU_HASH bucket[%d] < symbias{%#x}\n", |
8583 | 13 | bj, symbias); |
8584 | 13 | } |
8585 | 87.7k | if (bmax < bj) { |
8586 | 3.05k | bmax = bj; |
8587 | 3.05k | } |
8588 | 87.7k | } |
8589 | 112k | } |
8590 | 863 | if (1==n_bucket && 0==buckets[0] |
8591 | 179 | && 1==n_bitmask && 0==bitmask[0]) { |
8592 | | // 2021-09-11 Rust on RaspberryPi apparently uses this to minimize space. |
8593 | | // But then the DT_GNU_HASH symbol lookup algorithm always fails? |
8594 | | // https://github.com/upx/upx/issues/525 |
8595 | 39 | } else |
8596 | 824 | if (bmax) { |
8597 | 675 | if ((1+ bmax) < symbias) { |
8598 | 7 | throwCantPack("bad DT_GNU_HASH (1+ max_bucket)=%#x < symbias=%#x", |
8599 | 7 | 1+ bmax, symbias); |
8600 | 7 | } |
8601 | 668 | bmax -= symbias; |
8602 | 668 | } |
8603 | | |
8604 | 856 | unsigned r = 0; |
8605 | 856 | if (!n_bucket || !n_bitmask || !v_sym |
8606 | 795 | || (r=1, ((-1+ n_bitmask) & n_bitmask)) // not a power of 2 |
8607 | 753 | || (r=2, (8*sizeof(upx_uint64_t) <= gnu_shift)) // shifted result always == 0 |
8608 | 753 | || (r=3, (n_bucket>>30)) // fie on fuzzers |
8609 | 753 | || (r=4, (n_bitmask>>30)) |
8610 | 753 | || (r=5, ((file_size/sizeof(unsigned)) |
8611 | 753 | <= ((sizeof(*bitmask)/sizeof(unsigned))*n_bitmask + 2*n_bucket))) // FIXME: weak |
8612 | 750 | || (r=6, ((v_gsh < v_sym) && (v_sym - v_gsh) < (sizeof(unsigned)*4 // headers |
8613 | 436 | + sizeof(*bitmask)*n_bitmask // bitmask |
8614 | 436 | + sizeof(*buckets)*n_bucket // buckets |
8615 | 436 | + sizeof(*hasharr)*(!bmax ? 0 : (1+ bmax)) // hasharr |
8616 | 436 | )) ) |
8617 | 856 | ) { |
8618 | 166 | throwCantPack("bad DT_GNU_HASH n_bucket=%#x n_bitmask=%#x len=%#lx r=%d", |
8619 | 166 | n_bucket, n_bitmask, (long unsigned)(v_sym - v_gsh), r); |
8620 | 166 | } |
8621 | 856 | } |
8622 | 1.88k | e_shstrndx = get_te16(&ehdri.e_shstrndx); // who omitted this? |
8623 | 1.88k | if (e_shnum <= e_shstrndx |
8624 | 278 | && !(0==e_shnum && 0==e_shstrndx) ) { |
8625 | 87 | throwCantPack("bad .e_shstrndx %d >= .e_shnum %d", e_shstrndx, e_shnum); |
8626 | 87 | } |
8627 | 1.88k | } |
8628 | | |
8629 | | unsigned PackLinuxElf::gnu_hash(char const *q) |
8630 | 2.14k | { |
8631 | 2.14k | unsigned char const *p = (unsigned char const *)q; |
8632 | 2.14k | unsigned h; |
8633 | | |
8634 | 23.6k | for (h= 5381; 0!=*p; ++p) { |
8635 | 21.4k | h += *p + (h << 5); |
8636 | 21.4k | } |
8637 | 2.14k | return h; |
8638 | 2.14k | } |
8639 | | |
8640 | | unsigned PackLinuxElf::elf_hash(char const *p) |
8641 | 2.02k | { |
8642 | 2.02k | unsigned h; |
8643 | 22.2k | for (h= 0; 0!=*p; ++p) { |
8644 | 20.2k | h = *p + (h<<4); |
8645 | 20.2k | { |
8646 | 20.2k | unsigned const t = 0xf0000000u & h; |
8647 | 20.2k | h &= ~t; |
8648 | 20.2k | h ^= t>>24; |
8649 | 20.2k | } |
8650 | 20.2k | } |
8651 | 2.02k | return h; |
8652 | 2.02k | } |
8653 | | |
8654 | | Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const |
8655 | 3.75k | { |
8656 | 3.75k | if (hashtab && dynsym && dynstr) { |
8657 | 1.68k | unsigned const n_bucket = get_te32(&hashtab[0]); |
8658 | 1.68k | unsigned const *const buckets = &hashtab[2]; |
8659 | 1.68k | unsigned const *const chains = &buckets[n_bucket]; |
8660 | | // Find the end of DT_HASH and DT_DYNSYM. Perhaps elf_find_table_size() |
8661 | | // depends on too many valid input values? |
8662 | 1.68k | void const *l_hash = nullptr, *l_sym = nullptr; |
8663 | 5.08k | for (unsigned j = 0; j < DT_NUM; ++j) { |
8664 | 5.08k | void const *const ptr = dt_offsets[j] + (char const *)file_image.getVoidPtr(); |
8665 | 5.08k | if (!l_hash && hashtab == ptr) { |
8666 | 1.64k | l_hash = dt_offsets[1+ j] + (char const *)file_image.getVoidPtr(); |
8667 | 1.64k | } |
8668 | 5.08k | if (!l_sym && dynsym == ptr) { |
8669 | 1.64k | l_sym = dt_offsets[1+ j] + (char const *)file_image.getVoidPtr(); |
8670 | 1.64k | } |
8671 | 5.08k | if (l_sym && l_hash) |
8672 | 1.63k | break; // found both |
8673 | 3.44k | if (this->file_size == (off_t)dt_offsets[j]) |
8674 | 51 | break; // end sentinel |
8675 | 3.44k | } |
8676 | 1.68k | if (n_bucket) { |
8677 | 1.35k | void const *EOM = file_size + (char const *)file_image.getVoidPtr(); |
8678 | 1.35k | unsigned const m = elf_hash(name) % n_bucket; |
8679 | 1.35k | unsigned n_visit = 0; |
8680 | 1.35k | unsigned si; |
8681 | 1.35k | if (l_hash <= &buckets[m]) |
8682 | 7 | throwCantPack("bad DT_HASH %u", m); |
8683 | 4.60k | for (si= get_te32(&buckets[m]); si; si = get_te32(&chains[si])) { |
8684 | 3.34k | if (l_sym <= &dynsym[si]) |
8685 | 42 | throwCantPack("bad DT_HASH chain %d\n", si); |
8686 | 3.30k | char const *const p= get_dynsym_name(si, (unsigned)-1); |
8687 | 3.30k | if (p && 0==strcmp(name, p)) |
8688 | 32 | return &dynsym[si]; |
8689 | 3.27k | if (l_sym <= &dynsym[n_visit++]) |
8690 | 13 | throwCantPack("circular DT_HASH chain %d\n", si); |
8691 | | // Detect next si out-of-bounds |
8692 | 3.25k | if ((unsigned)((unsigned int const *)EOM - chains) <= si) |
8693 | 2 | throwCantPack("bad DT_HASH chain %d\n", si); |
8694 | 3.25k | } |
8695 | 1.34k | } |
8696 | 1.68k | } |
8697 | 3.66k | if (gashtab && dynsym && dynstr) { |
8698 | 1.50k | unsigned const n_bucket = get_te32(&gashtab[0]); |
8699 | 1.50k | unsigned const symbias = get_te32(&gashtab[1]); |
8700 | 1.50k | unsigned const n_bitmask = get_te32(&gashtab[2]); |
8701 | 1.50k | unsigned const gnu_shift = get_te32(&gashtab[3]); |
8702 | 1.50k | unsigned const *const bitmask = &gashtab[4]; |
8703 | 1.50k | unsigned const *const buckets = &bitmask[n_bitmask]; |
8704 | 1.50k | unsigned const *const hasharr = &buckets[n_bucket]; |
8705 | 1.50k | if (31 < gnu_shift) { |
8706 | 36 | throwCantPack("bad gnu_shift %#x", gnu_shift); |
8707 | 36 | } |
8708 | 1.46k | if ((file_size + file_image) <= (void const *)hasharr) { |
8709 | 1 | throwCantPack("bad n_bucket %#x\n", n_bucket); |
8710 | 1 | } |
8711 | 1.46k | if (!n_bitmask |
8712 | 1.46k | || (unsigned)(file_size - ((char const *)bitmask - (char const *)(void const *)file_image)) |
8713 | 1.46k | <= sizeof(unsigned)*n_bitmask ) { |
8714 | 1 | throwCantPack("bad n_bitmask %#x\n", n_bitmask); |
8715 | 1 | } |
8716 | 1.46k | if (n_bucket) { // -rust-musl can have "empty" hashtab |
8717 | 1.45k | unsigned const h = gnu_hash(name); |
8718 | 1.45k | unsigned const hbit1 = 037& h; |
8719 | 1.45k | unsigned const hbit2 = 037& (h>>gnu_shift); |
8720 | 1.45k | unsigned const w = get_te32(&bitmask[(n_bitmask -1) & (h>>5)]); |
8721 | | |
8722 | 1.45k | if (1& (w>>hbit1) & (w>>hbit2)) { |
8723 | 394 | unsigned const hhead = get_te32(&buckets[h % n_bucket]); |
8724 | 394 | if (symnum_max <= hhead || (hhead && hhead < symbias)) { |
8725 | 85 | throwCantPack("bad DT_GNU_HASH symnum_max{%#x} <= buckets[%d]{%#x} < symbias{%#x}\n", |
8726 | 85 | symnum_max, h % n_bucket, hhead, symbias); |
8727 | 85 | } |
8728 | 309 | if (hhead) { |
8729 | 205 | Elf32_Sym const *dsp = &dynsym[hhead]; |
8730 | 205 | unsigned const *hp = &hasharr[hhead - symbias]; |
8731 | 205 | unsigned k; |
8732 | 735 | do { |
8733 | 735 | if (gashend <= hp) { |
8734 | 22 | throwCantPack("bad DT_GNU_HASH[%#x] head=%u", |
8735 | 22 | (unsigned)(hp - hasharr), hhead); |
8736 | 22 | } |
8737 | 713 | k = get_te32(hp); |
8738 | 713 | if (0==((h ^ k)>>1)) { |
8739 | 0 | unsigned const st_name = get_te32(&dsp->st_name); |
8740 | 0 | char const *const p = get_str_name(st_name, (unsigned)-1); |
8741 | 0 | if (0==strcmp(name, p)) { |
8742 | 0 | return dsp; |
8743 | 0 | } |
8744 | 0 | } |
8745 | 713 | } while (++dsp, ++hp, 0==(1u& k)); |
8746 | 205 | } |
8747 | 309 | } |
8748 | 1.45k | } |
8749 | 1.46k | } |
8750 | | // 2021-12-25 FIXME: Some Rust programs use |
8751 | | // (1==n_bucket && 0==buckets[0] && 1==n_bitmask && 0==bitmask[0]) |
8752 | | // to minimize space in DT_GNU_HASH. This causes the fancy lookup to fail. |
8753 | | // Is a fallback to linear search assumed? |
8754 | | // 2022-03-12 Some Rust programs have 0==n_bucket. |
8755 | 3.51k | return nullptr; |
8756 | | |
8757 | 3.66k | } |
8758 | | |
8759 | | Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const |
8760 | 2.07k | { |
8761 | 2.07k | if (hashtab && dynsym && dynstr) { |
8762 | 939 | unsigned const n_bucket = get_te32(&hashtab[0]); |
8763 | 939 | unsigned const *const buckets = &hashtab[2]; |
8764 | 939 | unsigned const *const chains = &buckets[n_bucket]; |
8765 | | // Find the end of DT_HASH and DT_DYNSYM. Perhaps elf_find_table_size() |
8766 | | // depends on too many valid input values? |
8767 | 939 | void const *l_hash = nullptr, *l_sym = nullptr; |
8768 | 3.06k | for (unsigned j = 0; j < DT_NUM; ++j) { |
8769 | 3.06k | void const *const ptr = dt_offsets[j] + (char const *)file_image.getVoidPtr(); |
8770 | 3.06k | if (!l_hash && hashtab == ptr) { |
8771 | 884 | l_hash = dt_offsets[1+ j] + (char const *)file_image.getVoidPtr(); |
8772 | 884 | } |
8773 | 3.06k | if (!l_sym && dynsym == ptr) { |
8774 | 922 | l_sym = dt_offsets[1+ j] + (char const *)file_image.getVoidPtr(); |
8775 | 922 | } |
8776 | 3.06k | if (l_sym && l_hash) |
8777 | 872 | break; // found both |
8778 | 2.19k | if (this->file_size == (off_t)dt_offsets[j]) |
8779 | 67 | break; //end |
8780 | 2.19k | } |
8781 | 939 | if (n_bucket) { // -rust-musl can have "empty" hashtab |
8782 | 671 | void const *const EOM = file_size + (char const *)file_image.getVoidPtr(); |
8783 | 671 | unsigned const m = elf_hash(name) % n_bucket; |
8784 | 671 | unsigned n_visit = 0; |
8785 | 671 | unsigned si; |
8786 | 671 | if (l_hash <= &buckets[m]) |
8787 | 46 | throwCantPack("bad DT_HASH %u", m); |
8788 | 8.58k | for (si= get_te32(&buckets[m]); si; si = get_te32(&chains[si])) { |
8789 | 8.09k | if (l_sym <= &dynsym[si]) |
8790 | 96 | throwCantPack("bad DT_HASH chain %d\n", si); |
8791 | 8.00k | char const *const p= get_dynsym_name(si, (unsigned)-1); |
8792 | 8.00k | if (p && 0==strcmp(name, p)) |
8793 | 10 | return &dynsym[si]; |
8794 | 7.99k | if (l_sym <= &dynsym[n_visit++]) |
8795 | 24 | throwCantPack("circular DT_HASH chain %d\n", si); |
8796 | | // Detect next si out-of-bounds |
8797 | 7.96k | if ((unsigned)((unsigned int const *)EOM - chains) <= si) |
8798 | 6 | throwCantPack("bad DT_HASH chain %d\n", si); |
8799 | 7.96k | } |
8800 | 625 | } |
8801 | 939 | } |
8802 | 1.88k | if (gashtab && dynsym && dynstr) { |
8803 | 708 | unsigned const n_bucket = get_te32(&gashtab[0]); |
8804 | 708 | unsigned const symbias = get_te32(&gashtab[1]); |
8805 | 708 | unsigned const n_bitmask = get_te32(&gashtab[2]); |
8806 | 708 | unsigned const gnu_shift = get_te32(&gashtab[3]); |
8807 | 708 | upx_uint64_t const *const bitmask = (upx_uint64_t const *)(void const *)&gashtab[4]; |
8808 | 708 | unsigned const *const buckets = (unsigned const *)&bitmask[n_bitmask]; |
8809 | 708 | unsigned const *const hasharr = &buckets[n_bucket]; |
8810 | | |
8811 | 708 | if (31 < gnu_shift) { |
8812 | 2 | throwCantPack("bad gnu_shift %#x", gnu_shift); |
8813 | 2 | } |
8814 | 706 | if ((file_size + file_image) <= (void const *)hasharr) { |
8815 | 1 | throwCantPack("bad n_bucket %#x\n", n_bucket); |
8816 | 1 | } |
8817 | 705 | if (!n_bitmask |
8818 | 704 | || (unsigned)(file_size - ((char const *)bitmask - (char const *)(void const *)file_image)) |
8819 | 704 | <= sizeof(unsigned)*n_bitmask ) { |
8820 | 1 | throwCantPack("bad n_bitmask %#x\n", n_bitmask); |
8821 | 1 | } |
8822 | 704 | if (n_bucket) { // -rust-musl can have "empty" gashtab |
8823 | 694 | unsigned const h = gnu_hash(name); |
8824 | 694 | unsigned const hbit1 = 077& h; |
8825 | 694 | unsigned const hbit2 = 077& (h>>gnu_shift); |
8826 | 694 | upx_uint64_t const w = get_te64(&bitmask[(n_bitmask -1) & (h>>6)]); |
8827 | 694 | if (1& (w>>hbit1) & (w>>hbit2)) { |
8828 | 290 | unsigned hhead = get_te32(&buckets[h % n_bucket]); |
8829 | 290 | if (symnum_max <= hhead || (hhead && hhead < symbias)) { |
8830 | 83 | throwCantPack("bad DT_GNU_HASH symnum_max{%#x} <= buckets[%d]{%#x} < symbias{%#x}\n", |
8831 | 83 | symnum_max, h % n_bucket, hhead, symbias); |
8832 | 83 | } |
8833 | 207 | if (hhead) { |
8834 | 129 | Elf64_Sym const *dsp = &dynsym[hhead]; |
8835 | 129 | unsigned const *hp = &hasharr[hhead - symbias]; |
8836 | 129 | unsigned k; |
8837 | 1.44k | do { |
8838 | 1.44k | if (gashend <= hp) { |
8839 | 13 | throwCantPack("bad gnu_hash[%#tx] head=%u", |
8840 | 13 | hp - hasharr, hhead); |
8841 | 13 | } |
8842 | 1.43k | k = get_te32(hp); |
8843 | 1.43k | if (0==((h ^ k)>>1)) { |
8844 | 0 | unsigned const st_name = get_te32(&dsp->st_name); |
8845 | 0 | char const *const p = get_str_name(st_name, (unsigned)-1); |
8846 | 0 | if (0==strcmp(name, p)) { |
8847 | 0 | return dsp; |
8848 | 0 | } |
8849 | 0 | } |
8850 | 1.43k | } while (++dsp, ++hp, 0==(1u& k)); |
8851 | 129 | } |
8852 | 207 | } |
8853 | 694 | } |
8854 | 704 | } |
8855 | | // 2021-12-25 FIXME: Some Rust programs use |
8856 | | // (1==n_bucket && 0==buckets[0] && 1==n_bitmask && 0==bitmask[0]) |
8857 | | // to minimize space in DT_GNU_HASH. This causes the fancy lookup to fail. |
8858 | | // Is a fallback to linear search assumed? |
8859 | | // 2022-03-12 Some Rust programs have 0==n_bucket. |
8860 | 1.78k | return nullptr; |
8861 | | |
8862 | 1.88k | } |
8863 | | |
8864 | | void PackLinuxElf32::unpack(OutputFile *fo) |
8865 | 789 | { |
8866 | 789 | if (e_phoff != sizeof(Elf32_Ehdr)) {// Phdrs not contiguous with Ehdr |
8867 | 0 | throwCantUnpack("bad e_phoff"); |
8868 | 0 | } |
8869 | 789 | unsigned const c_phnum = get_te16(&ehdri.e_phnum); |
8870 | 789 | unsigned u_phnum = 0; |
8871 | 789 | upx_uint32_t old_dtinit = 0; |
8872 | | |
8873 | 789 | if (Elf32_Ehdr::ET_EXEC == get_te16(&ehdri.e_type)) { |
8874 | | // 40fddf17153ee3db73a04ff1bf288b91676138d6 2001-02-01 ph.version 11; b_info 12 bytes |
8875 | | // df9db96bd1c013c07da1d7ec740021d588ab2815 2001-01-17 ph.version 11; no b_info (==> 8 bytes) |
8876 | 754 | if (ph.version <= 11 |
8877 | 2 | && get_te32(&ehdri.e_entry) < 0x401180 |
8878 | 1 | && get_te16(&ehdri.e_machine)==Elf32_Ehdr::EM_386) { |
8879 | | // old style, 8-byte b_info: |
8880 | | // sizeof(b_info.sz_unc) + sizeof(b_info.sz_cpr); |
8881 | 1 | szb_info = 2*sizeof(unsigned); |
8882 | 1 | } |
8883 | 754 | } |
8884 | | |
8885 | 789 | fi->seek(overlay_offset - sizeof(l_info), SEEK_SET); |
8886 | 789 | fi->readx(&linfo, sizeof(linfo)); |
8887 | 789 | if (UPX_MAGIC_LE32 != get_le32(&linfo.l_magic)) { |
8888 | 103 | NE32 const *const lp = (NE32 const *)(void const *)&linfo; |
8889 | | // Workaround for bug of extra linfo by some asl_pack2_Shdrs(). |
8890 | 103 | if (0==lp[0] && 0==lp[1] && 0==lp[2]) { // looks like blank extra |
8891 | 10 | fi->readx(&linfo, sizeof(linfo)); |
8892 | 10 | if (UPX_MAGIC_LE32 == get_le32(&linfo.l_magic)) { |
8893 | 2 | overlay_offset += sizeof(linfo); |
8894 | 2 | } |
8895 | 8 | else { |
8896 | 8 | throwCantUnpack("l_info corrupted"); |
8897 | 8 | } |
8898 | 10 | } |
8899 | 93 | else { |
8900 | 93 | throwCantUnpack("l_info corrupted"); |
8901 | 93 | } |
8902 | 103 | } |
8903 | 688 | lsize = get_te16(&linfo.l_lsize); |
8904 | 688 | p_info hbuf; fi->readx(&hbuf, sizeof(hbuf)); |
8905 | 688 | unsigned orig_file_size = get_te32(&hbuf.p_filesize); |
8906 | 688 | blocksize = get_te32(&hbuf.p_blocksize); |
8907 | 688 | if ((u32_t)file_size > orig_file_size || blocksize > orig_file_size |
8908 | 658 | || (orig_file_size >> 8) > (u32_t)file_size // heuristic anti-fuzz |
8909 | 592 | || (blocksize >> 8) > (u32_t)file_size |
8910 | 592 | || !mem_size_valid(1, blocksize, OVERHEAD)) |
8911 | 92 | throwCantUnpack("p_info corrupted"); |
8912 | | |
8913 | 596 | ibuf.alloc(blocksize + OVERHEAD); |
8914 | 596 | b_info bhdr; memset(&bhdr, 0, sizeof(bhdr)); |
8915 | 596 | fi->readx(&bhdr, szb_info); |
8916 | 596 | ph.u_len = get_te32(&bhdr.sz_unc); |
8917 | 596 | ph.c_len = get_te32(&bhdr.sz_cpr); |
8918 | 596 | ph.set_method(bhdr.b_method, overlay_offset + sizeof(p_info)); |
8919 | 596 | if (ph.c_len > (unsigned)file_size || ph.c_len == 0 || ph.u_len == 0 |
8920 | 559 | || ph.u_len > orig_file_size) |
8921 | 39 | throwCantUnpack("b_info corrupted"); |
8922 | 557 | ph.filter_cto = bhdr.b_cto8; |
8923 | 557 | prev_method = bhdr.b_method; // FIXME if multiple de-compressors |
8924 | | |
8925 | 557 | MemBuffer u(ph.u_len); |
8926 | 557 | Elf32_Ehdr *const ehdr = (Elf32_Ehdr *)&u[0]; |
8927 | 557 | Elf32_Phdr const *phdr = nullptr; |
8928 | 557 | total_in = 0; |
8929 | 557 | total_out = 0; |
8930 | 557 | unsigned c_adler = upx_adler32(nullptr, 0); |
8931 | 557 | unsigned u_adler = upx_adler32(nullptr, 0); |
8932 | | |
8933 | 557 | unsigned is_shlib = 0; |
8934 | 557 | loader_offset = 0; |
8935 | 557 | MemBuffer o_elfhdrs; |
8936 | 557 | Elf32_Phdr const *const dynhdr = elf_find_ptype(Elf32_Phdr::PT_DYNAMIC, phdri, c_phnum); |
8937 | | // dynseg was set by PackLinuxElf32help1 |
8938 | 557 | if (dynhdr && !(Elf32_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf32_Dyn::DT_FLAGS_1))) { |
8939 | | // Packed shlib? (ET_DYN without -fPIE) |
8940 | 158 | is_shlib = 1; |
8941 | 158 | xct_off = overlay_offset - sizeof(l_info); |
8942 | 158 | u_phnum = get_te16(&ehdri.e_phnum); |
8943 | 158 | o_elfhdrs.alloc(sz_elf_hdrs); |
8944 | 158 | un_shlib_1(fo, o_elfhdrs, c_adler, u_adler, orig_file_size); |
8945 | 158 | *ehdr = ehdri; |
8946 | 158 | } |
8947 | 399 | else { // main executable |
8948 | | // Uncompress Ehdr and Phdrs: info for control of unpacking |
8949 | 399 | if (ibuf.getSize() < ph.c_len) |
8950 | 2 | throwCompressedDataViolation(); |
8951 | 397 | fi->readx(ibuf, ph.c_len); |
8952 | 397 | if (ph.u_len < sizeof(*ehdr)) |
8953 | 5 | throwCantUnpack("ElfXX_Ehdr corrupted"); |
8954 | 392 | decompress(ibuf, (upx_byte *)ehdr, false); |
8955 | 392 | if (ehdr->e_type !=ehdri.e_type |
8956 | 304 | || ehdr->e_machine!=ehdri.e_machine |
8957 | 304 | || ehdr->e_version!=ehdri.e_version |
8958 | | // less strict for EM_PPC to workaround earlier bug |
8959 | 304 | || !( ehdr->e_flags==ehdri.e_flags |
8960 | 22 | || Elf32_Ehdr::EM_PPC == get_te16(&ehdri.e_machine)) |
8961 | 300 | || ehdr->e_ehsize !=ehdri.e_ehsize |
8962 | | // check EI_MAG[0-3], EI_CLASS, EI_DATA, EI_VERSION |
8963 | 297 | || memcmp(ehdr->e_ident, ehdri.e_ident, Elf32_Ehdr::EI_OSABI)) { |
8964 | 13 | throwCantUnpack("ElfXX_Ehdr corrupted"); |
8965 | 13 | } |
8966 | | // Rewind: prepare for data phase |
8967 | 379 | fi->seek(- (off_t) (szb_info + ph.c_len), SEEK_CUR); |
8968 | | |
8969 | 379 | u_phnum = get_te16(&ehdr->e_phnum); |
8970 | 379 | if ((umin(MAX_ELF_HDR_32, ph.u_len) - sizeof(Elf32_Ehdr))/sizeof(Elf32_Phdr) < u_phnum) { |
8971 | 2 | throwCantUnpack("bad compressed e_phnum"); |
8972 | 2 | } |
8973 | 377 | o_elfhdrs.alloc(sizeof(Elf32_Ehdr) + u_phnum * sizeof(Elf32_Phdr)); |
8974 | 377 | memcpy(o_elfhdrs, ehdr, o_elfhdrs.getSize()); |
8975 | | |
8976 | | // Decompress each PT_LOAD. |
8977 | 377 | bool first_PF_X = true; |
8978 | 377 | phdr = (Elf32_Phdr *) (void *) (1+ ehdr); // uncompressed |
8979 | 1.37k | for (unsigned j=0; j < u_phnum; ++phdr, ++j) { |
8980 | 1.00k | if (is_LOAD(phdr)) { |
8981 | 432 | unsigned const filesz = get_te32(&phdr->p_filesz); |
8982 | 432 | unsigned const offset = get_te32(&phdr->p_offset); |
8983 | 432 | if (fo) { |
8984 | 223 | fo->seek(offset, SEEK_SET); |
8985 | 223 | if (total_out < offset) { |
8986 | 57 | total_out = offset; // FIXME: can it be re-write? |
8987 | 57 | } |
8988 | 223 | } |
8989 | 432 | if (Elf32_Phdr::PF_X & get_te32(&phdr->p_flags)) { |
8990 | 295 | unpackExtent(filesz, fo, |
8991 | 295 | c_adler, u_adler, first_PF_X); |
8992 | 295 | first_PF_X = false; |
8993 | 295 | } |
8994 | 137 | else { |
8995 | 137 | unpackExtent(filesz, fo, |
8996 | 137 | c_adler, u_adler, false); |
8997 | 137 | } |
8998 | 432 | } |
8999 | 1.00k | } |
9000 | 377 | } |
9001 | | |
9002 | 535 | upx_uint32_t const e_entry = get_te32(&ehdri.e_entry); |
9003 | 535 | unsigned off_entry = 0; |
9004 | 535 | phdr = phdri; |
9005 | 535 | load_va = 0; |
9006 | 1.24k | for (unsigned j=0; j < c_phnum; ++j, ++phdr) { |
9007 | 812 | if (is_LOAD(phdr)) { |
9008 | 169 | upx_uint32_t offset = get_te32(&phdr->p_offset); |
9009 | 169 | upx_uint32_t vaddr = get_te32(&phdr->p_vaddr); |
9010 | 169 | upx_uint32_t filesz = get_te32(&phdr->p_filesz); |
9011 | 169 | if (!load_va) { |
9012 | 146 | load_va = vaddr; |
9013 | 146 | } |
9014 | 169 | if ((e_entry - vaddr) < filesz) { |
9015 | 100 | off_entry = (e_entry - vaddr) + offset; |
9016 | 100 | break; |
9017 | 100 | } |
9018 | 169 | } |
9019 | 812 | } |
9020 | 535 | unsigned d_info[6]; |
9021 | 535 | unsigned sz_d_info = sizeof(d_info); |
9022 | 535 | if (!is_shlib) { |
9023 | 95 | if (get_te32(&phdri[0].p_flags) & Elf32_Phdr::PF_X) { |
9024 | | // Old style, such as upx-3.91 thru upx-3.95 |
9025 | 56 | switch (this->e_machine) { |
9026 | 0 | default: { |
9027 | 0 | char msg[40]; snprintf(msg, sizeof(msg), |
9028 | 0 | "Unknown architecture %d", this->e_machine); |
9029 | 0 | throwCantUnpack(msg); |
9030 | 0 | }; break; |
9031 | 9 | case Elf32_Ehdr::EM_MIPS:sz_d_info = 1 * sizeof(unsigned); break; |
9032 | 19 | case Elf32_Ehdr::EM_ARM: sz_d_info = 4 * sizeof(unsigned); break; |
9033 | 8 | case Elf32_Ehdr::EM_PPC: sz_d_info = 3 * sizeof(unsigned); break; |
9034 | 20 | case Elf32_Ehdr::EM_386: sz_d_info = 2 * sizeof(unsigned); break; |
9035 | 56 | } |
9036 | 56 | } |
9037 | 95 | loader_offset = off_entry - sz_d_info; |
9038 | 95 | } |
9039 | | |
9040 | 535 | if (0x1000==get_te32(&phdri[0].p_filesz) // detect C_BASE style |
9041 | 41 | && 0==get_te32(&phdri[1].p_offset) |
9042 | 36 | && 0==get_te32(&phdri[0].p_offset) |
9043 | 29 | && get_te32(&phdri[1].p_filesz) == get_te32(&phdri[1].p_memsz)) { |
9044 | 23 | fi->seek(up4(get_te32(&phdri[1].p_memsz)), SEEK_SET); // past the loader |
9045 | 23 | } |
9046 | 512 | else if (is_shlib |
9047 | 77 | || (off_entry + up4(lsize) + ph.getPackHeaderSize() + sizeof(overlay_offset)) |
9048 | 128 | < up4(file_size)) { |
9049 | | // Loader is not at end; skip past it. |
9050 | 128 | if (loader_offset) { |
9051 | 128 | fi->seek(loader_offset, SEEK_SET); |
9052 | 128 | } |
9053 | 0 | else { |
9054 | 0 | funpad4(fi); // MATCH01 |
9055 | 0 | } |
9056 | 128 | fi->readx(d_info, sz_d_info); |
9057 | 128 | if (is_shlib && 0==old_dtinit) { |
9058 | 56 | old_dtinit = get_te32(&d_info[2 + (0==d_info[0])]); |
9059 | 56 | is_asl = 1u& get_te32(&d_info[0 + (0==d_info[0])]); |
9060 | 56 | } |
9061 | 128 | fi->seek(lsize - sz_d_info, SEEK_CUR); |
9062 | 128 | } |
9063 | | |
9064 | | // The gaps between PT_LOAD and after last PT_LOAD |
9065 | 535 | phdr = (Elf32_Phdr const *)(1+ (Elf32_Ehdr const *)(void const *)o_elfhdrs); |
9066 | 535 | upx_uint32_t hi_offset(0); |
9067 | 1.15k | for (unsigned j = 0; j < u_phnum; ++j) { |
9068 | 620 | if (is_LOAD(&phdr[j]) |
9069 | 199 | && hi_offset < get_te32(&phdr[j].p_offset)) |
9070 | 114 | hi_offset = get_te32(&phdr[j].p_offset); |
9071 | 620 | } |
9072 | 995 | for (unsigned j = 0; j < u_phnum; ++j) { |
9073 | 487 | unsigned const size = find_LOAD_gap(phdr, j, u_phnum); |
9074 | 487 | if (size) { |
9075 | 153 | unsigned const where = get_te32(&phdr[j].p_offset) + |
9076 | 153 | get_te32(&phdr[j].p_filesz); |
9077 | 153 | if (fo) |
9078 | 71 | fo->seek(where, SEEK_SET); |
9079 | 153 | { // Recover from some piracy [also serves as error tolerance :-) ] |
9080 | | // Getting past the loader is problematic, due to unintended |
9081 | | // variances between released versions: |
9082 | | // l_info.l_lsize might be rounded up by 8 instead of by 4, and |
9083 | | // sz_d_info might have changed. |
9084 | 153 | b_info b_peek, *bp = &b_peek; |
9085 | 153 | fi->readx(bp, sizeof(b_peek)); |
9086 | 153 | upx_off_t pos = fi->seek(-(off_t)sizeof(b_peek), SEEK_CUR); |
9087 | 153 | unsigned sz_unc = get_te32(&bp->sz_unc); |
9088 | 153 | unsigned sz_cpr = get_te32(&bp->sz_cpr); |
9089 | 153 | unsigned word3 = get_te32(&bp->b_method); |
9090 | 153 | unsigned method = bp->b_method; |
9091 | 153 | unsigned ftid = bp->b_ftid; |
9092 | 153 | unsigned cto8 = bp->b_cto8; |
9093 | 153 | if (!( ((sz_cpr == sz_unc) && (0 == word3) && (size == sz_unc)) // incompressible literal |
9094 | 149 | || ((sz_cpr < sz_unc) |
9095 | 113 | && (method == prev_method || M_NRV2B_LE32 == prev_method) |
9096 | 81 | && (0 == ftid) && (0 == cto8)) ) |
9097 | 153 | ) { |
9098 | 69 | opt->info_mode++; |
9099 | 69 | infoWarning("bad b_info at %#zx", (size_t)pos); |
9100 | 69 | unsigned const N_PEEK(16 * sizeof(int)), H_PEEK(N_PEEK >> 1); |
9101 | 69 | unsigned char peek_arr[N_PEEK]; |
9102 | 69 | fi->seek(pos - H_PEEK, SEEK_SET); |
9103 | 69 | fi->readx(peek_arr, sizeof(peek_arr)); |
9104 | 69 | fi->seek(pos, SEEK_SET); |
9105 | 69 | bool const is_be = ELFDATA2MSB == ehdri.e_ident[EI_DATA]; |
9106 | 69 | if (is_be) { |
9107 | | // Does the right thing for sz_unc and sz_cpr, |
9108 | | // but swaps b_method and b_extra. Need find_be32() :-) |
9109 | 459 | for (unsigned k = 0; k < N_PEEK; k += sizeof(int)) { |
9110 | 432 | set_le32(&peek_arr[k], get_be32(&peek_arr[k])); |
9111 | 432 | } |
9112 | 27 | } |
9113 | 69 | int boff = find_le32(peek_arr, sizeof(peek_arr), size); |
9114 | 69 | if (boff < 0 || sizeof(peek_arr) < (sizeof(*bp) + boff)) { |
9115 | 27 | throwCantUnpack("b_info corrupted"); |
9116 | 27 | } |
9117 | 42 | bp = (b_info *)(void *)&peek_arr[boff]; |
9118 | | |
9119 | 42 | sz_unc = get_le32(&bp->sz_unc); |
9120 | 42 | sz_cpr = get_le32(&bp->sz_cpr); |
9121 | 42 | word3 = get_le32(&bp->b_method); |
9122 | 42 | ftid = bp->b_ftid; |
9123 | 42 | cto8 = bp->b_cto8; |
9124 | 42 | if (0 <= boff // found |
9125 | 41 | && ( ((sz_cpr == sz_unc) && (0 == word3) && (size == sz_unc)) // incompressible literal |
9126 | 37 | || ((sz_cpr < sz_unc) && (0 == ftid) && (0 == cto8) |
9127 | 29 | && ((is_be ? bp->b_extra : bp->b_method) == prev_method)) ) |
9128 | 42 | ) { |
9129 | 27 | pos -= H_PEEK; |
9130 | 27 | pos += boff; |
9131 | 27 | infoWarning("... recovery at %#zx", (size_t)pos); |
9132 | 27 | fi->seek(pos, SEEK_SET); |
9133 | 27 | } |
9134 | 42 | opt->info_mode--; |
9135 | 42 | } |
9136 | 153 | } |
9137 | 126 | unpackExtent(size, fo, |
9138 | 126 | c_adler, u_adler, false, |
9139 | 126 | (hi_offset != get_te32(&phdr[j].p_offset))); |
9140 | 126 | } |
9141 | 487 | } |
9142 | | |
9143 | | // check for end-of-file |
9144 | 508 | fi->readx(&bhdr, szb_info); |
9145 | 508 | ph.set_method(bhdr.b_method, ~0u); |
9146 | 508 | unsigned const sz_unc = ph.u_len = get_te32(&bhdr.sz_unc); |
9147 | | |
9148 | 508 | if (sz_unc == 0) { // uncompressed size 0 -> EOF |
9149 | | // note: magic is always stored le32 |
9150 | 51 | unsigned const sz_cpr = get_le32(&bhdr.sz_cpr); |
9151 | 51 | if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic |
9152 | 14 | throwCompressedDataViolation(); |
9153 | 51 | } |
9154 | 457 | else { // extra bytes after end? |
9155 | 457 | throwCompressedDataViolation(); |
9156 | 457 | } |
9157 | | |
9158 | 37 | if (is_shlib) { |
9159 | 2 | un_DT_INIT(old_dtinit, (Elf32_Phdr *)(1+ (Elf32_Ehdr *)(void *)o_elfhdrs), dynhdr, fo); |
9160 | 2 | } |
9161 | | |
9162 | | // update header with totals |
9163 | 37 | ph.c_len = total_in; |
9164 | 37 | ph.u_len = total_out; |
9165 | | |
9166 | | // all bytes must be written |
9167 | 37 | if (fo && total_out != orig_file_size) |
9168 | 0 | throwEOFException(); |
9169 | | |
9170 | | // finally test the checksums |
9171 | 37 | if (ph.c_adler != c_adler || ph.u_adler != u_adler) |
9172 | 2 | throwChecksumError(); |
9173 | 37 | } |
9174 | | |
9175 | | void PackLinuxElf::unpack(OutputFile * /*fo*/) |
9176 | 0 | { |
9177 | 0 | throwCantUnpack("internal error"); |
9178 | 0 | } |
9179 | | |
9180 | | // NOLINTEND(clang-analyzer-deadcode.DeadStores) |
9181 | | // NOLINTEND(clang-analyzer-core.CallAndMessage) |
9182 | | |
9183 | | /* vim:set ts=4 sw=4 et: */ |