mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
More care in ::forward_Shdrs() and ::pack4()
Also, de-compressing arm64 shlib restores .init_array[0], although supposedly *_RELATIVE relocation should overwrite. https://github.com/upx/upx/issues/693 modified: p_lx_elf.cpp modified: p_lx_elf.h
This commit is contained in:
parent
fa364d6ea3
commit
75e153dd99
109
src/p_lx_elf.cpp
109
src/p_lx_elf.cpp
|
@ -5023,7 +5023,6 @@ int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
|
|||
? 0
|
||||
: e_shnum * sizeof(Elf32_Shdr))));
|
||||
memcpy(lowmem, file_image, xct_off); // android omits Shdr here
|
||||
|
||||
}
|
||||
unsigned nk_f = 0; upx_uint32_t xsz_f = 0;
|
||||
for (k = 0; k < e_phnum; ++k)
|
||||
|
@ -5576,15 +5575,15 @@ void PackLinuxElf32mipsel::defineSymbols(Filter const *ft)
|
|||
// because compression gives smaller extents, with no reasonable _Shdr fields.
|
||||
// At least gdb can continue.
|
||||
|
||||
void PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
||||
unsigned PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
||||
{
|
||||
if (!fo) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
unsigned penalty = total_out;
|
||||
if (saved_opt_android_shlib) { // Forward select _Shdr
|
||||
unsigned penalty = total_out;
|
||||
// Keep _Shdr for rtld data (below xct_off).
|
||||
// Discard _Shdr for compressed regions, except ".text" for gdb
|
||||
// Discard _Shdr for compressed regions, except ".text" for gdb.
|
||||
// Keep _Shdr for SHF_WRITE.
|
||||
// Discard _Shdr with (0==sh_addr), except _Shdr[0]
|
||||
// Keep ARM_ATTRIBUTES
|
||||
|
@ -5708,7 +5707,6 @@ void PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
|||
fo->seek(0, SEEK_SET);
|
||||
fo->rewrite(eho, sizeof(*eho));
|
||||
fo->seek(0, SEEK_END);
|
||||
info("Android penalty = %d bytes", penalty = total_out - penalty); (void)penalty;
|
||||
}
|
||||
else if (sec_arm_attr) {
|
||||
// Forward just ARM_ATTRIBUTES
|
||||
|
@ -5745,15 +5743,18 @@ void PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
|||
fo->rewrite(eho, sizeof(*eho));
|
||||
fo->seek(0, SEEK_END);
|
||||
}
|
||||
penalty = total_out - penalty;
|
||||
info("Android penalty = %d bytes", penalty);
|
||||
return penalty;
|
||||
}
|
||||
|
||||
void PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|
||||
unsigned PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|
||||
{
|
||||
if (!fo) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
unsigned penalty = total_out;
|
||||
if (saved_opt_android_shlib) { // Forward select _Shdr
|
||||
unsigned penalty = total_out;
|
||||
// Keep _Shdr for rtld data (below xct_off).
|
||||
// Discard _Shdr for compressed regions, except ".text" for gdb.
|
||||
// Keep _Shdr for SHF_WRITE.
|
||||
|
@ -5879,7 +5880,6 @@ void PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|
|||
fo->seek(0, SEEK_SET);
|
||||
fo->rewrite(eho, sizeof(*eho));
|
||||
fo->seek(0, SEEK_END);
|
||||
info("Android penalty = %d bytes", penalty = total_out - penalty); (void)penalty;
|
||||
}
|
||||
else if (sec_arm_attr) {
|
||||
// Forward just ARM_ATTRIBUTES
|
||||
|
@ -5916,6 +5916,9 @@ void PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|
|||
fo->rewrite(eho, sizeof(*eho));
|
||||
fo->seek(0, SEEK_END);
|
||||
}
|
||||
penalty = total_out - penalty;
|
||||
info("Android penalty = %d bytes", penalty);
|
||||
return penalty;
|
||||
}
|
||||
|
||||
void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
||||
|
@ -5927,32 +5930,28 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
|||
cprElfHdr4 *eho = !xct_off
|
||||
? (cprElfHdr4 *)(void *)&elfout // not shlib FIXME: ugly casting
|
||||
: (cprElfHdr4 *)lowmem.getVoidPtr(); // shlib
|
||||
forward_Shdrs(fo, &eho->ehdr);
|
||||
unsigned penalty = forward_Shdrs(fo, &eho->ehdr); (void)penalty;
|
||||
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
if (opt->o_unix.preserve_build_id) { // FIXME: co-ordinate with forward_Shdrs
|
||||
// calc e_shoff here and write shdrout, then o_shstrtab
|
||||
//NOTE: these are pushed last to ensure nothing is stepped on
|
||||
//for the UPX structure.
|
||||
unsigned const len = fpad4(fo, total_out);
|
||||
set_te32(&eho->ehdr.e_shoff,len);
|
||||
total_out = fpad4(fo, total_out);
|
||||
set_te32(&eho->ehdr.e_shoff, total_out);
|
||||
|
||||
int const ssize = sizeof(shdrout);
|
||||
unsigned const ssize = sizeof(shdrout);
|
||||
unsigned const ssize1 = get_te32(&shdrout.shdr[1].sh_size);
|
||||
unsigned const ssize2 = get_te32(&shdrout.shdr[2].sh_size);
|
||||
|
||||
shdrout.shdr[2].sh_offset = len+ssize;
|
||||
shdrout.shdr[1].sh_offset = shdrout.shdr[2].sh_offset+shdrout.shdr[2].sh_size;
|
||||
set_te32(&shdrout.shdr[2].sh_offset, ssize + total_out);
|
||||
set_te32(&shdrout.shdr[1].sh_offset, ssize2 + ssize + total_out);
|
||||
|
||||
fo->write(&shdrout, ssize);
|
||||
fo->write(&shdrout, ssize); total_out += ssize;
|
||||
|
||||
fo->write(o_shstrtab,shdrout.shdr[2].sh_size);
|
||||
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
||||
fo->write(o_shstrtab, ssize2); total_out += ssize2;
|
||||
fo->write(buildid_data, ssize1); total_out += ssize1;
|
||||
}
|
||||
|
||||
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
||||
// tries to make .bss, which requires PF_W.
|
||||
// But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X.
|
||||
set_te32(&eho->phdr[C_TEXT].p_filesz, sz_pack2 + lsize);
|
||||
eho->phdr[C_TEXT].p_memsz = eho->phdr[C_TEXT].p_filesz;
|
||||
|
||||
// ph.u_len and ph.c_len are leftover from earliest days when there was
|
||||
// only one compressed extent. Use a good analogy for multiple extents.
|
||||
ph.u_len = file_size;
|
||||
|
@ -5968,7 +5967,7 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
|||
}
|
||||
}
|
||||
if (!sec_arm_attr && !saved_opt_android_shlib) {
|
||||
// Make it abunantly clear that there are no Elf32_Shdr in this shlib
|
||||
// Make it abundantly clear that there are no Elf32_Shdr in this shlib
|
||||
eho->ehdr.e_shoff = 0;
|
||||
set_te16(&eho->ehdr.e_shentsize, sizeof(Elf32_Shdr)); // Android bug: cannot use 0
|
||||
eho->ehdr.e_shnum = 0;
|
||||
|
@ -5987,6 +5986,12 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
|||
}
|
||||
}
|
||||
else { // not shlib
|
||||
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
||||
// tries to make .bss, which requires PF_W.
|
||||
// But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X.
|
||||
set_te32(&eho->phdr[C_TEXT].p_filesz, sz_pack2 + lsize);
|
||||
eho->phdr[C_TEXT].p_memsz = eho->phdr[C_TEXT].p_filesz;
|
||||
|
||||
Elf32_Phdr *phdr = &eho->phdr[C_NOTE];
|
||||
if (PT_NOTE32== get_te32(&phdr->p_type)) {
|
||||
upx_uint32_t const reloc = get_te32(&eho->phdr[C_TEXT].p_vaddr);
|
||||
|
@ -5994,12 +5999,9 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
|||
reloc + get_te32(&phdr->p_vaddr));
|
||||
set_te32( &phdr->p_paddr,
|
||||
reloc + get_te32(&phdr->p_paddr));
|
||||
fo->rewrite(eho, sz_elf_hdrs);
|
||||
// FIXME fo->rewrite(&elfnote, sizeof(elfnote));
|
||||
}
|
||||
else {
|
||||
fo->rewrite(eho, sz_elf_hdrs);
|
||||
}
|
||||
fo->rewrite(eho, sz_elf_hdrs);
|
||||
fo->rewrite(&linfo, sizeof(linfo));
|
||||
}
|
||||
}
|
||||
|
@ -6013,32 +6015,28 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
|||
cprElfHdr4 *eho = !xct_off
|
||||
? &elfout // not shlib
|
||||
: (cprElfHdr4 *)lowmem.getVoidPtr(); // shlib
|
||||
forward_Shdrs(fo, &eho->ehdr);
|
||||
unsigned penalty = forward_Shdrs(fo, &eho->ehdr); (void)penalty;
|
||||
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
if (opt->o_unix.preserve_build_id) { // FIXME: co-ordinate with forward_Shdrs
|
||||
// calc e_shoff here and write shdrout, then o_shstrtab
|
||||
//NOTE: these are pushed last to ensure nothing is stepped on
|
||||
//for the UPX structure.
|
||||
unsigned const len = fpad4(fo, total_out);
|
||||
set_te64(&eho->ehdr.e_shoff,len);
|
||||
total_out = fpad4(fo, total_out);
|
||||
set_te64(&eho->ehdr.e_shoff, total_out);
|
||||
|
||||
int const ssize = sizeof(shdrout);
|
||||
unsigned const ssize = sizeof(shdrout);
|
||||
unsigned const ssize1 = get_te64(&shdrout.shdr[1].sh_size);
|
||||
unsigned const ssize2 = get_te64(&shdrout.shdr[2].sh_size);
|
||||
|
||||
shdrout.shdr[2].sh_offset = len+ssize;
|
||||
shdrout.shdr[1].sh_offset = shdrout.shdr[2].sh_offset+shdrout.shdr[2].sh_size;
|
||||
set_te64(&shdrout.shdr[2].sh_offset, ssize + total_out);
|
||||
set_te64(&shdrout.shdr[1].sh_offset, ssize2 + ssize + total_out);
|
||||
|
||||
fo->write(&shdrout, ssize);
|
||||
fo->write(&shdrout, ssize); total_out += ssize;
|
||||
|
||||
fo->write(o_shstrtab,shdrout.shdr[2].sh_size);
|
||||
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
||||
fo->write(o_shstrtab, ssize2); total_out += ssize2;
|
||||
fo->write(buildid_data, ssize1); total_out += ssize1;
|
||||
}
|
||||
|
||||
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
||||
// tries to make .bss, which requires PF_W.
|
||||
// But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X.
|
||||
set_te64(&eho->phdr[C_TEXT].p_filesz, sz_pack2 + lsize);
|
||||
eho->phdr[C_TEXT].p_memsz = eho->phdr[C_TEXT].p_filesz;
|
||||
|
||||
// ph.u_len and ph.c_len are leftover from earliest days when there was
|
||||
// only one compressed extent. Use a good analogy for multiple extents.
|
||||
ph.u_len = file_size;
|
||||
|
@ -6054,7 +6052,7 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
|||
}
|
||||
}
|
||||
if (!sec_arm_attr && !saved_opt_android_shlib) {
|
||||
// Make it abunantly clear that there are no Elf64_Shdr in this shlib
|
||||
// Make it abundantly clear that there are no Elf64_Shdr in this shlib
|
||||
eho->ehdr.e_shoff = 0;
|
||||
set_te16(&eho->ehdr.e_shentsize, sizeof(Elf64_Shdr)); // Android bug: cannot use 0
|
||||
eho->ehdr.e_shnum = 0;
|
||||
|
@ -6074,6 +6072,12 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
|||
}
|
||||
}
|
||||
else { // not shlib
|
||||
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
||||
// tries to make .bss, which requires PF_W.
|
||||
// But strict SELinux (or PaX, grSecurity) disallows PF_W with PF_X.
|
||||
set_te64(&eho->phdr[C_TEXT].p_filesz, sz_pack2 + lsize);
|
||||
eho->phdr[C_TEXT].p_memsz = eho->phdr[C_TEXT].p_filesz;
|
||||
|
||||
Elf64_Phdr *phdr = &eho->phdr[C_NOTE];
|
||||
if (PT_NOTE64 == get_te32(&phdr->p_type)) {
|
||||
upx_uint64_t const reloc = get_te64(&eho->phdr[C_TEXT].p_vaddr);
|
||||
|
@ -6081,12 +6085,9 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
|||
reloc + get_te64(&phdr->p_vaddr));
|
||||
set_te64( &phdr->p_paddr,
|
||||
reloc + get_te64(&phdr->p_paddr));
|
||||
fo->rewrite(eho, sz_elf_hdrs);
|
||||
// FIXME fo->rewrite(&elfnote, sizeof(elfnote));
|
||||
}
|
||||
else {
|
||||
fo->rewrite(eho, sz_elf_hdrs);
|
||||
}
|
||||
fo->rewrite(eho, sz_elf_hdrs);
|
||||
fo->rewrite(&linfo, sizeof(linfo));
|
||||
}
|
||||
}
|
||||
|
@ -6981,12 +6982,14 @@ void PackLinuxElf64::un_DT_INIT(
|
|||
}
|
||||
|
||||
// Set arr[0] to the first user init routine.
|
||||
// Elf64_Rela overwrites anyway, so this is a redundancy
|
||||
// or a Don't Care.
|
||||
unsigned r_info = get_te64(&rp->r_info);
|
||||
unsigned r_type = ELF64_R_TYPE(r_info);
|
||||
u64_t word;
|
||||
if (Elf64_Ehdr::EM_ARM64 == e_machine) {
|
||||
if (R_AARCH64_RELATIVE == r_type) {
|
||||
word = 0; // Elf64_Rela overwrites *(.r_offset) !
|
||||
set_te64(&word, init_rva); // old_dtinit ?
|
||||
}
|
||||
else if (R_AARCH64_ABS64 == r_type) {
|
||||
word = 0;
|
||||
|
|
|
@ -155,7 +155,7 @@ protected:
|
|||
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
||||
virtual off_t pack3(OutputFile *, Filter &) override; // append loader
|
||||
virtual void pack4(OutputFile *, Filter &) override; // append pack header
|
||||
virtual void forward_Shdrs(OutputFile *fo, Elf32_Ehdr *ehdro);
|
||||
virtual unsigned forward_Shdrs(OutputFile *fo, Elf32_Ehdr *ehdro);
|
||||
virtual void unpack(OutputFile *fo) override;
|
||||
virtual void un_asl_dynsym(unsigned orig_file_size, OutputFile *);
|
||||
virtual void un_shlib_1(
|
||||
|
@ -319,7 +319,7 @@ protected:
|
|||
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
||||
virtual off_t pack3(OutputFile *, Filter &) override; // append loader
|
||||
virtual void pack4(OutputFile *, Filter &) override; // append pack header
|
||||
virtual void forward_Shdrs(OutputFile *fo, Elf64_Ehdr *ehdro);
|
||||
virtual unsigned forward_Shdrs(OutputFile *fo, Elf64_Ehdr *ehdro);
|
||||
virtual void unpack(OutputFile *fo) override;
|
||||
virtual void un_asl_dynsym(unsigned orig_file_size, OutputFile *);
|
||||
virtual void un_shlib_1(
|
||||
|
|
Loading…
Reference in New Issue
Block a user