Revamp --android-shlib
Android "Oreo" wants to deal with ElfXX_Shdr[]. So splice 4KiB into PT_LOAD[0] with an "extra" copy of them. This requires careful relocation processing. It also costs a page at run time, and an average of a page in the file (depending on fragmentation at the boundary between r-x and rw- .) https://github.com/upx/upx/issues/124 https://github.com/upx/upx/issues/139 https://github.com/upx/upx/issues/142 modified: p_elf_enum.h modified: p_lx_elf.cpp modified: p_lx_elf.h modified: stub/src/arm.v4a-linux.shlib-init.S modified: stub/src/arm.v4t-linux.shlib-init.S modified: stub/src/arm64-linux.shlib-init.S modified: stub/arm.v5a-linux.shlib-init.h modified: stub/arm.v5t-linux.shlib-init.h modified: stub/arm64-linux.shlib-init.h modified: ../.github/travis_testsuite_1.sh
This commit is contained in:
+421
-245
@@ -87,6 +87,7 @@ fpad4(OutputFile *fo)
|
||||
return d + len;
|
||||
}
|
||||
|
||||
#if 0 //{ unused
|
||||
static off_t
|
||||
fpad8(OutputFile *fo)
|
||||
{
|
||||
@@ -96,6 +97,7 @@ fpad8(OutputFile *fo)
|
||||
fo->write(&zero, d);
|
||||
return d + len;
|
||||
}
|
||||
#endif //}
|
||||
|
||||
static unsigned
|
||||
funpad4(InputFile *fi)
|
||||
@@ -268,8 +270,8 @@ PackLinuxElf32::PackLinuxElf32help1(InputFile *f)
|
||||
alloc_file_image(file_image, file_size);
|
||||
f->seek(0, SEEK_SET);
|
||||
f->readx(file_image, file_size);
|
||||
phdri= (Elf32_Phdr *)(e_phoff + file_image); // do not free() !!
|
||||
shdri= (Elf32_Shdr const *)(e_shoff + file_image); // do not free() !!
|
||||
phdri= (Elf32_Phdr *)(e_phoff + file_image); // do not free() !!
|
||||
shdri= (Elf32_Shdr *)(e_shoff + file_image); // do not free() !!
|
||||
sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM);
|
||||
if (sec_dynsym) {
|
||||
unsigned t = get_te32(&sec_dynsym->sh_link);
|
||||
@@ -307,8 +309,8 @@ off_t PackLinuxElf::pack3(OutputFile *fo, Filter &ft) // return length of output
|
||||
fo->write(&zero, t);
|
||||
len += t;
|
||||
|
||||
set_te32(&disp, 2*sizeof(disp) + len - (sz_elf_hdrs + sizeof(p_info) + sizeof(l_info)));
|
||||
fo->write(&disp, sizeof(disp)); // .e_entry - &first_b_info
|
||||
set_te32(&disp, sz_elf_hdrs + sizeof(p_info) + sizeof(l_info));
|
||||
fo->write(&disp, sizeof(disp)); // offset(b_info)
|
||||
len += sizeof(disp);
|
||||
set_te32(&disp, len); // distance back to beginning (detect dynamic reloc)
|
||||
fo->write(&disp, sizeof(disp));
|
||||
@@ -319,15 +321,21 @@ off_t PackLinuxElf::pack3(OutputFile *fo, Filter &ft) // return length of output
|
||||
? jni_onload_va
|
||||
: elf_unsigned_dynamic(Elf32_Dyn::DT_INIT) );
|
||||
set_te32(&disp, firstpc_va - load_va);
|
||||
fo->write(&disp, sizeof(disp));
|
||||
if (opt->o_unix.android_shlib) { // the extra page
|
||||
set_te32(&disp, asl_delta + firstpc_va - load_va);
|
||||
}
|
||||
fo->write(&disp, sizeof(disp)); // DT_INIT.d_val
|
||||
len += sizeof(disp);
|
||||
|
||||
set_te32(&disp, hatch_off);
|
||||
fo->write(&disp, sizeof(disp));
|
||||
fo->write(&disp, sizeof(disp)); // offset(hatch)
|
||||
len += sizeof(disp);
|
||||
|
||||
if (opt->o_unix.android_shlib) {
|
||||
xct_off += asl_delta; // the extra page
|
||||
}
|
||||
set_te32(&disp, xct_off);
|
||||
fo->write(&disp, sizeof(disp));
|
||||
fo->write(&disp, sizeof(disp)); // offset(dst for f_exp)
|
||||
len += sizeof(disp);
|
||||
}
|
||||
sz_pack2 = len; // 0 mod 8
|
||||
@@ -362,6 +370,8 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
|
||||
fo->write(&hdr, sizeof(hdr));
|
||||
flen = fpad4(fo);
|
||||
|
||||
set_te32(&elfout.phdr[0].p_filesz, sz_pack2 + lsize);
|
||||
set_te32(&elfout.phdr[0].p_memsz, sz_pack2 + lsize);
|
||||
if (0==xct_off) { // not shared library; adjust PT_LOAD
|
||||
v_hole = page_mask & (~page_mask + v_hole + get_te32(&elfout.phdr[0].p_vaddr));
|
||||
set_te32(&elfout.phdr[1].p_vaddr, v_hole);
|
||||
@@ -398,8 +408,8 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
|
||||
set_te32(&phdr->p_align, align);
|
||||
}
|
||||
off += (align-1) & (ioff - off);
|
||||
fi->seek(ioff, SEEK_SET); fi->readx(ibuf, len);
|
||||
fo->seek( off, SEEK_SET); fo->write(ibuf, len);
|
||||
fo->seek( off, SEEK_SET);
|
||||
fo->write(ioff + file_image, len);
|
||||
so_slide = off - ioff;
|
||||
set_te32(&phdr->p_offset, so_slide + ioff);
|
||||
}
|
||||
@@ -436,9 +446,25 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
|
||||
fo->rewrite(&word, sizeof(word));
|
||||
flen = fo->seek(0, SEEK_END);
|
||||
}
|
||||
ehdri.e_shnum = 0;
|
||||
ehdri.e_shoff = 0;
|
||||
ehdri.e_shstrndx = 0;
|
||||
if (opt->o_unix.android_shlib) {
|
||||
// Update {DYNAMIC}.sh_offset by so_slide.
|
||||
Elf32_Shdr *shdr = shdri;
|
||||
for (unsigned j = 0; j < e_shnum; ++shdr, ++j) {
|
||||
if (Elf32_Shdr::SHT_DYNAMIC == get_te32(&shdr->sh_type)) {
|
||||
upx_uint32_t offset = get_te32(&shdr->sh_offset);
|
||||
set_te32(&shdr->sh_offset, so_slide - asl_delta + offset );
|
||||
fo->seek(j * sizeof(Elf32_Shdr) - asl_delta + xct_off, SEEK_SET);
|
||||
fo->rewrite(shdr, sizeof(*shdr));
|
||||
fo->seek(0, SEEK_END);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // !opt->o_unix.android_shlib)
|
||||
ehdri.e_shnum = 0;
|
||||
ehdri.e_shoff = 0;
|
||||
ehdri.e_shstrndx = 0;
|
||||
}
|
||||
}
|
||||
return flen;
|
||||
}
|
||||
@@ -522,8 +548,8 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
||||
set_te64(&phdr->p_align, align);
|
||||
}
|
||||
off += (align-1) & (ioff - off);
|
||||
fi->seek(ioff, SEEK_SET); fi->readx(ibuf, len);
|
||||
fo->seek( off, SEEK_SET); fo->write(ibuf, len);
|
||||
fo->seek( off, SEEK_SET);
|
||||
fo->write(ioff + file_image, len);
|
||||
so_slide = off - ioff;
|
||||
set_te64(&phdr->p_offset, so_slide + ioff);
|
||||
}
|
||||
@@ -553,15 +579,40 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
||||
if (xct_off < ioff)
|
||||
set_te64(&phdr->p_offset, so_slide + ioff);
|
||||
} // end each Phdr
|
||||
|
||||
if (off_init) { // change DT_INIT.d_val
|
||||
fo->seek(off_init, SEEK_SET);
|
||||
upx_uint64_t word; set_te64(&word, va_init);
|
||||
fo->rewrite(&word, sizeof(word));
|
||||
flen = fo->seek(0, SEEK_END);
|
||||
}
|
||||
ehdri.e_shnum = 0;
|
||||
ehdri.e_shoff = 0;
|
||||
ehdri.e_shstrndx = 0;
|
||||
if (opt->o_unix.android_shlib) {
|
||||
// Update {DYNAMIC}.sh_offset by so_slide.
|
||||
Elf64_Shdr *shdr = shdri;
|
||||
for (unsigned j = 0; j < e_shnum; ++shdr, ++j) {
|
||||
unsigned sh_type = get_te32(&shdr->sh_type);
|
||||
if (Elf64_Shdr::SHT_DYNAMIC == sh_type) {
|
||||
upx_uint64_t offset = get_te64(&shdr->sh_offset);
|
||||
set_te64(&shdr->sh_offset, so_slide - asl_delta + offset );
|
||||
fo->seek(j * sizeof(Elf64_Shdr) - asl_delta + xct_off, SEEK_SET);
|
||||
fo->rewrite(shdr, sizeof(*shdr));
|
||||
fo->seek(0, SEEK_END);
|
||||
break;
|
||||
}
|
||||
if (Elf64_Shdr::SHT_RELA == sh_type
|
||||
&& n_jmp_slot
|
||||
&& !strcmp(".rela.plt", get_te32(&shdr->sh_name) + shstrtab)) {
|
||||
upx_uint64_t f_off = elf_get_offset_from_address(plt_off);
|
||||
fo->seek(f_off, SEEK_SET);
|
||||
fo->rewrite(&file_image[f_off - so_slide], n_jmp_slot * sizeof(void *));
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // !opt->o_unix.android_shlib)
|
||||
ehdri.e_shnum = 0;
|
||||
ehdri.e_shoff = 0;
|
||||
ehdri.e_shstrndx = 0;
|
||||
}
|
||||
}
|
||||
return flen;
|
||||
}
|
||||
@@ -703,8 +754,8 @@ PackLinuxElf64::PackLinuxElf64help1(InputFile *f)
|
||||
alloc_file_image(file_image, file_size);
|
||||
f->seek(0, SEEK_SET);
|
||||
f->readx(file_image, file_size);
|
||||
phdri= (Elf64_Phdr *)(e_phoff + file_image); // do not free() !!
|
||||
shdri= (Elf64_Shdr const *)(e_shoff + file_image); // do not free() !!
|
||||
phdri= (Elf64_Phdr *)(e_phoff + file_image); // do not free() !!
|
||||
shdri= (Elf64_Shdr *)(e_shoff + file_image); // do not free() !!
|
||||
sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM);
|
||||
if (sec_dynsym) {
|
||||
unsigned t = get_te32(&sec_dynsym->sh_link);
|
||||
@@ -1718,7 +1769,37 @@ bool PackLinuxElf32::canPack()
|
||||
// Also allow __uClibc_main and __uClibc_start_main .
|
||||
|
||||
if (Elf32_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) {
|
||||
// The DT_SYMTAB has no designated length. Read the whole file.
|
||||
alloc_file_image(file_image, file_size);
|
||||
fi->seek(0, SEEK_SET);
|
||||
fi->readx(file_image, file_size);
|
||||
memcpy(&ehdri, ehdr, sizeof(Elf32_Ehdr));
|
||||
phdri= (Elf32_Phdr *)((size_t)e_phoff + file_image); // do not free() !!
|
||||
shdri= (Elf32_Shdr *)((size_t)e_shoff + file_image); // do not free() !!
|
||||
|
||||
sec_strndx = &shdri[get_te16(&ehdr->e_shstrndx)];
|
||||
shstrtab = (char const *)(get_te32(&sec_strndx->sh_offset) + file_image);
|
||||
sec_dynsym = elf_find_section_type(Elf32_Shdr::SHT_DYNSYM);
|
||||
if (sec_dynsym)
|
||||
sec_dynstr = get_te32(&sec_dynsym->sh_link) + shdri;
|
||||
|
||||
sec_strndx = &shdri[get_te16(&ehdr->e_shstrndx)];
|
||||
shstrtab = (char const *)(get_te32(&sec_strndx->sh_offset) + file_image);
|
||||
if (Elf32_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type)
|
||||
|| 0!=strcmp((char const *)".shstrtab",
|
||||
&shstrtab[get_te32(&sec_strndx->sh_name)]) ) {
|
||||
throwCantPack("bad e_shstrndx");
|
||||
}
|
||||
|
||||
phdr= phdri;
|
||||
for (int j= e_phnum; --j>=0; ++phdr)
|
||||
if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) {
|
||||
dynseg= (Elf32_Dyn const *)(check_pt_dynamic(phdr) + file_image);
|
||||
break;
|
||||
}
|
||||
// elf_find_dynamic() returns 0 if 0==dynseg.
|
||||
dynstr= (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB);
|
||||
dynsym= (Elf32_Sym const *)elf_find_dynamic(Elf32_Dyn::DT_SYMTAB);
|
||||
|
||||
if (Elf32_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf32_Dyn::DT_FLAGS_1)
|
||||
|| calls_crt1((Elf32_Rel const *)elf_find_dynamic(Elf32_Dyn::DT_REL),
|
||||
@@ -1898,14 +1979,20 @@ PackLinuxElf64::canPack()
|
||||
fi->seek(0, SEEK_SET);
|
||||
fi->readx(file_image, file_size);
|
||||
memcpy(&ehdri, ehdr, sizeof(Elf64_Ehdr));
|
||||
phdri= (Elf64_Phdr *)((size_t)e_phoff + file_image); // do not free() !!
|
||||
shdri= (Elf64_Shdr const *)((size_t)e_shoff + file_image); // do not free() !!
|
||||
phdri= (Elf64_Phdr *)((size_t)e_phoff + file_image); // do not free() !!
|
||||
shdri= (Elf64_Shdr *)((size_t)e_shoff + file_image); // do not free() !!
|
||||
|
||||
//sec_strndx = &shdri[ehdr->e_shstrndx];
|
||||
//shstrtab = (char const *)(sec_strndx->sh_offset + file_image);
|
||||
sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM);
|
||||
if (sec_dynsym)
|
||||
sec_dynstr = get_te64(&sec_dynsym->sh_link) + shdri;
|
||||
sec_dynstr = get_te32(&sec_dynsym->sh_link) + shdri;
|
||||
|
||||
sec_strndx = &shdri[get_te16(&ehdr->e_shstrndx)];
|
||||
shstrtab = (char const *)(get_te64(&sec_strndx->sh_offset) + file_image);
|
||||
if (Elf64_Shdr::SHT_STRTAB != get_te32(&sec_strndx->sh_type)
|
||||
|| 0!=strcmp((char const *)".shstrtab",
|
||||
&shstrtab[get_te32(&sec_strndx->sh_name)]) ) {
|
||||
throwCantPack("bad e_shstrndx");
|
||||
}
|
||||
|
||||
phdr= phdri;
|
||||
for (int j= e_phnum; --j>=0; ++phdr)
|
||||
@@ -1945,9 +2032,23 @@ PackLinuxElf64::canPack()
|
||||
}
|
||||
Elf64_Shdr const *shdr = shdri;
|
||||
xct_va = ~0ull;
|
||||
for (int j= e_shnum; --j>=0; ++shdr) {
|
||||
if (Elf64_Shdr::SHF_EXECINSTR & get_te32(&shdr->sh_flags)) {
|
||||
xct_va = umin64(xct_va, get_te64(&shdr->sh_addr));
|
||||
if (e_shnum) {
|
||||
for (int j= e_shnum; --j>=0; ++shdr) {
|
||||
if (Elf64_Shdr::SHF_EXECINSTR & get_te32(&shdr->sh_flags)) {
|
||||
xct_va = umin64(xct_va, get_te64(&shdr->sh_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // no Sections; use heuristics
|
||||
upx_uint64_t const strsz = elf_unsigned_dynamic(Elf64_Dyn::DT_STRSZ);
|
||||
upx_uint64_t const strtab = elf_unsigned_dynamic(Elf64_Dyn::DT_STRTAB);
|
||||
upx_uint64_t const relsz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELSZ);
|
||||
upx_uint64_t const rel = elf_unsigned_dynamic(Elf64_Dyn::DT_REL);
|
||||
upx_uint64_t const init = elf_unsigned_dynamic(Elf64_Dyn::DT_INIT);
|
||||
if ((init == (relsz + rel ) && rel == (strsz + strtab))
|
||||
|| (init == (strsz + strtab) && strtab == (relsz + rel ))
|
||||
) {
|
||||
xct_va = init;
|
||||
}
|
||||
}
|
||||
// Rely on 0==elf_unsigned_dynamic(tag) if no such tag.
|
||||
@@ -2404,6 +2505,10 @@ PackLinuxElf64::generateElfHdr(
|
||||
}
|
||||
}
|
||||
|
||||
#define WANT_REL_ENUM
|
||||
#include "p_elf_enum.h"
|
||||
#undef WANT_REL_ENUM
|
||||
|
||||
void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
{
|
||||
fi->seek(0, SEEK_SET);
|
||||
@@ -2412,7 +2517,7 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
sz_phdrs = e_phnum * get_te16(&ehdri.e_phentsize);
|
||||
|
||||
// Remember all PT_NOTE, and find lg2_page from PT_LOAD.
|
||||
Elf32_Phdr const *phdr = phdri;
|
||||
Elf32_Phdr *phdr = phdri;
|
||||
note_size = 0;
|
||||
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
|
||||
if (phdr->PT_NOTE32 == get_te32(&phdr->p_type)) {
|
||||
@@ -2450,34 +2555,143 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
|
||||
progid = 0; // getRandomId(); not useful, so do not clutter
|
||||
if (0!=xct_off) { // shared library
|
||||
fi->seek(0, SEEK_SET);
|
||||
fi->readx(ibuf, xct_off);
|
||||
|
||||
sz_elf_hdrs = xct_off;
|
||||
fo->write(ibuf, xct_off);
|
||||
fo->write(file_image, xct_off); // before the first SHF_EXECINSTR (typ ".plt")
|
||||
if (opt->o_unix.android_shlib) {
|
||||
// In order to pacify the runtime linker on Android "O" ("Oreo"),
|
||||
// we will splice-in a 4KiB page that contains an "extra" copy
|
||||
// of the Shdr and shstrtab.
|
||||
xct_va += asl_delta;
|
||||
//xct_off += asl_delta; // not yet
|
||||
|
||||
// Relocate PT_DYNAMIC (in 2nd PT_LOAD)
|
||||
Elf32_Dyn *dyn = const_cast<Elf32_Dyn *>(dynseg);
|
||||
for (; dyn->d_tag; ++dyn) {
|
||||
unsigned d_tag = get_te32(&dyn->d_tag);
|
||||
if (Elf32_Dyn::DT_FINI == d_tag
|
||||
|| Elf32_Dyn::DT_FINI_ARRAY == d_tag
|
||||
|| Elf32_Dyn::DT_INIT_ARRAY == d_tag
|
||||
|| Elf32_Dyn::DT_PREINIT_ARRAY == d_tag
|
||||
|| Elf32_Dyn::DT_PLTGOT == d_tag) {
|
||||
unsigned d_val = get_te32(&dyn->d_val);
|
||||
set_te32(&dyn->d_val, asl_delta + d_val);
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate dynsym (DT_SYMTAB) which is below xct_va
|
||||
Elf32_Sym *sym = const_cast<Elf32_Sym *>(dynsym);
|
||||
unsigned off_dynsym = get_te32(&sec_dynsym->sh_offset);
|
||||
unsigned sz_dynsym = get_te32(&sec_dynsym->sh_size);
|
||||
for (int j = sz_dynsym / sizeof(Elf32_Sym); --j>=0; ++sym) {
|
||||
unsigned symval = get_te32(&sym->st_value);
|
||||
unsigned symsec = get_te16(&sym->st_shndx);
|
||||
if (Elf32_Sym::SHN_UNDEF != symsec
|
||||
&& Elf32_Sym::SHN_ABS != symsec
|
||||
&& xct_off <= symval) {
|
||||
set_te32(&sym->st_value, asl_delta + symval);
|
||||
}
|
||||
}
|
||||
fo->seek(off_dynsym, SEEK_SET); fo->rewrite(dynsym, sz_dynsym);
|
||||
|
||||
set_te32(&ehdri.e_shoff, sz_elf_hdrs);
|
||||
fo->seek(0, SEEK_SET); fo->rewrite(&ehdri, sizeof(ehdri));
|
||||
|
||||
// Relocate Phdr virtual addresses, but not physical offsets and sizes
|
||||
/* Elf32_Phdr * */ phdr = phdri;
|
||||
for (int j = e_phnum; --j>=0; ++phdr) {
|
||||
unsigned offset = get_te32(&phdr->p_offset);
|
||||
if (xct_off <= offset) { // above the extra page
|
||||
//set_te32(&phdr->p_offset, asl_delta + offset); // physical
|
||||
unsigned addr = get_te32(&phdr->p_paddr);
|
||||
set_te32(&phdr->p_paddr, asl_delta + addr);
|
||||
addr = get_te32(&phdr->p_vaddr);
|
||||
set_te32(&phdr->p_vaddr, asl_delta + addr);
|
||||
}
|
||||
// .p_filesz,.p_memsz are updated in ::pack3
|
||||
}
|
||||
fo->rewrite(phdri, e_phnum * sizeof(Elf32_Phdr)); // adjacent to Ehdr
|
||||
|
||||
// Relocate Shdr; and Rela, Rel (below xct_off)
|
||||
Elf32_Shdr *shdr = shdri;
|
||||
unsigned sz_shstrtab = get_te32(&sec_strndx->sh_size);
|
||||
for (int j = e_shnum; --j>=0; ++shdr) {
|
||||
unsigned sh_type = get_te32(&shdr->sh_type);
|
||||
unsigned sh_size = get_te32(&shdr->sh_size);
|
||||
unsigned sh_offset = get_te32(&shdr->sh_offset);
|
||||
unsigned sh_entsize = get_te32(&shdr->sh_entsize);
|
||||
if (xct_off <= sh_offset) {
|
||||
set_te32(&shdr->sh_offset, asl_delta + sh_offset);
|
||||
uint32_t addr = get_te32(&shdr->sh_addr);
|
||||
set_te32(&shdr->sh_addr, asl_delta + addr);
|
||||
}
|
||||
if (Elf32_Shdr::SHT_RELA== sh_type) {
|
||||
if (sizeof(Elf32_Rela) != sh_entsize) {
|
||||
char msg[50];
|
||||
snprintf(msg, sizeof(msg), "bad Rela.sh_entsize %u", sh_entsize);
|
||||
throwCantPack(msg);
|
||||
}
|
||||
Elf32_Rela *rela = (Elf32_Rela *)(sh_offset + file_image);
|
||||
for (int k = sh_size / sh_entsize; --k >= 0; ++rela) {
|
||||
unsigned r_offset = get_te32(&rela->r_offset);
|
||||
if (xct_off <= r_offset) {
|
||||
set_te32(&rela->r_offset, asl_delta + r_offset);
|
||||
}
|
||||
}
|
||||
fo->seek(sh_offset, SEEK_SET);
|
||||
fo->rewrite(sh_offset + file_image, sh_size);
|
||||
}
|
||||
if (Elf32_Shdr::SHT_REL == sh_type) {
|
||||
if (sizeof(Elf32_Rel) != sh_entsize) {
|
||||
char msg[50];
|
||||
snprintf(msg, sizeof(msg), "bad Rel.sh_entsize %u", sh_entsize);
|
||||
throwCantPack(msg);
|
||||
}
|
||||
Elf32_Rel *rel = (Elf32_Rel *)(sh_offset + file_image);
|
||||
for (int k = sh_size / sh_entsize; --k >= 0; ++rel) {
|
||||
unsigned r_offset = get_te32(&rel->r_offset);
|
||||
if (xct_off <= r_offset) {
|
||||
set_te32(&rel->r_offset, asl_delta + r_offset);
|
||||
}
|
||||
// r_offset must be in 2nd PT_LOAD; .p_vaddr was already relocated
|
||||
unsigned d = elf_get_offset_from_address(asl_delta + r_offset);
|
||||
unsigned w = get_te32(&file_image[d]);
|
||||
unsigned r_info = get_te32(&rel->r_info);
|
||||
unsigned r_type = ELF32_R_TYPE(r_info);
|
||||
if (xct_off <= w
|
||||
&& Elf32_Ehdr::EM_ARM == e_machine
|
||||
&& ( R_ARM_RELATIVE == r_type
|
||||
|| R_ARM_JUMP_SLOT == r_type)) {
|
||||
set_te32(&file_image[d], asl_delta + w);
|
||||
}
|
||||
}
|
||||
fo->seek(sh_offset, SEEK_SET);
|
||||
fo->rewrite(sh_offset + file_image, sh_size);
|
||||
}
|
||||
}
|
||||
|
||||
// New copy of Shdr
|
||||
set_te32(&sec_strndx->sh_offset, (e_shnum * sizeof(Elf32_Shdr)) + sz_elf_hdrs);
|
||||
fo->seek(xct_off, SEEK_SET); fo->write(shdri, e_shnum * sizeof(Elf32_Shdr));
|
||||
|
||||
// New copy of Shdr[.e_shstrndx].[ sh_offset, +.sh_size )
|
||||
fo->write(shstrtab, sz_shstrtab);
|
||||
|
||||
sz_elf_hdrs = fpad4(fo);
|
||||
//xct_off += asl_delta; // wait until ::pack3
|
||||
}
|
||||
memset(&linfo, 0, sizeof(linfo));
|
||||
fo->write(&linfo, sizeof(linfo));
|
||||
}
|
||||
|
||||
// if the preserve build-id option was specified
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
Elf32_Shdr *shdr = NULL;
|
||||
|
||||
Elf32_Shdr const *tmp = shdri;
|
||||
|
||||
if (! shdri) {
|
||||
shdr = New(Elf32_Shdr, e_shnum);
|
||||
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(ehdri.e_shoff,SEEK_SET);
|
||||
fi->readx((void*)shdr,ehdri.e_shentsize*ehdri.e_shnum);
|
||||
|
||||
// set this so we can use elf_find_section_name
|
||||
shdri = (Elf32_Shdr *)shdr;
|
||||
// set this so we can use elf_find_section_name
|
||||
e_shnum = get_te16(&ehdri.e_shnum);
|
||||
if (!shdri) {
|
||||
shdri = (Elf32_Shdr *)&file_image[get_te32(&ehdri.e_shoff)];
|
||||
}
|
||||
|
||||
//set the shstrtab
|
||||
sec_strndx = &shdri[ehdri.e_shstrndx];
|
||||
sec_strndx = &shdri[get_te16(&ehdri.e_shstrndx)];
|
||||
|
||||
char *strtab = New(char, sec_strndx->sh_size);
|
||||
fi->seek(0,SEEK_SET);
|
||||
@@ -2500,22 +2714,14 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
memset(&shdrout,0,sizeof(shdrout));
|
||||
|
||||
//setup the build-id
|
||||
memcpy(&shdrout.shdr[1],buildid, sizeof(shdrout.shdr[1]));
|
||||
memcpy(&shdrout.shdr[1], buildid, sizeof(shdrout.shdr[1]));
|
||||
shdrout.shdr[1].sh_name = 1;
|
||||
|
||||
//setup the shstrtab
|
||||
memcpy(&shdrout.shdr[2],sec_strndx, sizeof(shdrout.shdr[2]));
|
||||
memcpy(&shdrout.shdr[2], sec_strndx, sizeof(shdrout.shdr[2]));
|
||||
shdrout.shdr[2].sh_name = 20;
|
||||
shdrout.shdr[2].sh_size = 29; //size of our static shstrtab
|
||||
}
|
||||
|
||||
// repoint shdr in case it is used by code some where else
|
||||
if (shdr) {
|
||||
shdri = tmp;
|
||||
delete [] shdr;
|
||||
shdr = NULL;
|
||||
sec_strndx = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2620,7 +2826,7 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
assert(e_phoff == sizeof(Elf64_Ehdr)); // checked by canPack()
|
||||
sz_phdrs = e_phnum * get_te16(&ehdri.e_phentsize);
|
||||
|
||||
Elf64_Phdr const *phdr = phdri;
|
||||
Elf64_Phdr *phdr = phdri;
|
||||
note_size = 0;
|
||||
for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
|
||||
if (phdr->PT_NOTE64 == get_te32(&phdr->p_type)) {
|
||||
@@ -2655,11 +2861,154 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
|
||||
progid = 0; // getRandomId(); not useful, so do not clutter
|
||||
if (0!=xct_off) { // shared library
|
||||
fi->seek(0, SEEK_SET);
|
||||
fi->readx(ibuf, xct_off);
|
||||
|
||||
sz_elf_hdrs = xct_off;
|
||||
fo->write(ibuf, xct_off);
|
||||
fo->write(file_image, xct_off); // before the first SHF_EXECINSTR (typ ".plt")
|
||||
if (opt->o_unix.android_shlib) {
|
||||
// In order to pacify the runtime linker on Android "O" ("Oreo"),
|
||||
// we will splice-in a 4KiB page that contains an "extra" copy
|
||||
// of the Shdr and shstrtab.
|
||||
xct_va += asl_delta;
|
||||
//xct_off += asl_delta; // not yet
|
||||
|
||||
// Relocate PT_DYNAMIC (in 2nd PT_LOAD)
|
||||
Elf64_Dyn *dyn = const_cast<Elf64_Dyn *>(dynseg);
|
||||
for (; dyn->d_tag; ++dyn) {
|
||||
upx_uint64_t d_tag = get_te64(&dyn->d_tag);
|
||||
if (Elf64_Dyn::DT_FINI == d_tag
|
||||
|| Elf64_Dyn::DT_FINI_ARRAY == d_tag
|
||||
|| Elf64_Dyn::DT_INIT_ARRAY == d_tag
|
||||
|| Elf64_Dyn::DT_PREINIT_ARRAY == d_tag
|
||||
|| Elf64_Dyn::DT_PLTGOT == d_tag) {
|
||||
upx_uint64_t d_val = get_te64(&dyn->d_val);
|
||||
set_te64(&dyn->d_val, asl_delta + d_val);
|
||||
}
|
||||
}
|
||||
|
||||
// Relocate dynsym (DT_SYMTAB) which is below xct_va
|
||||
Elf64_Sym *sym = const_cast<Elf64_Sym *>(dynsym);
|
||||
upx_uint64_t off_dynsym = get_te64(&sec_dynsym->sh_offset);
|
||||
upx_uint64_t sz_dynsym = get_te64(&sec_dynsym->sh_size);
|
||||
for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) {
|
||||
upx_uint64_t symval = get_te64(&sym->st_value);
|
||||
unsigned symsec = get_te16(&sym->st_shndx);
|
||||
if (Elf64_Sym::SHN_UNDEF != symsec
|
||||
&& Elf64_Sym::SHN_ABS != symsec
|
||||
&& xct_off <= symval) {
|
||||
set_te64(&sym->st_value, asl_delta + symval);
|
||||
}
|
||||
}
|
||||
fo->seek(off_dynsym, SEEK_SET); fo->rewrite(dynsym, sz_dynsym);
|
||||
|
||||
set_te64(&ehdri.e_shoff, sz_elf_hdrs);
|
||||
fo->seek(0, SEEK_SET); fo->rewrite(&ehdri, sizeof(ehdri));
|
||||
|
||||
// Relocate Phdr virtual addresses, but not physical offsets and sizes
|
||||
/* Elf64_Phdr * */ phdr = phdri;
|
||||
for (int j = e_phnum; --j>=0; ++phdr) {
|
||||
upx_uint64_t offset = get_te64(&phdr->p_offset);
|
||||
if (xct_off <= offset) { // above the extra page
|
||||
//set_te64(&phdr->p_offset, asl_delta + offset); // physical
|
||||
upx_uint64_t addr = get_te64(&phdr->p_paddr);
|
||||
set_te64(&phdr->p_paddr, asl_delta + addr);
|
||||
addr = get_te64(&phdr->p_vaddr);
|
||||
set_te64(&phdr->p_vaddr, asl_delta + addr);
|
||||
}
|
||||
// .p_filesz,.p_memsz are updated in ::pack3
|
||||
}
|
||||
fo->rewrite(phdri, e_phnum * sizeof(Elf64_Phdr)); // adjacent to Ehdr
|
||||
|
||||
// Relocate Shdr; and Rela, Rel (below xct_off)
|
||||
Elf64_Shdr *shdr = shdri;
|
||||
upx_uint64_t sz_shstrtab = get_te64(&sec_strndx->sh_size);
|
||||
for (int j = e_shnum; --j>=0; ++shdr) {
|
||||
unsigned sh_type = get_te32(&shdr->sh_type);
|
||||
upx_uint64_t sh_size = get_te64(&shdr->sh_size);
|
||||
upx_uint64_t sh_offset = get_te64(&shdr->sh_offset);
|
||||
upx_uint64_t sh_entsize = get_te64(&shdr->sh_entsize);
|
||||
if (xct_off <= sh_offset) {
|
||||
set_te64(&shdr->sh_offset, asl_delta + sh_offset);
|
||||
upx_uint64_t addr = get_te64(&shdr->sh_addr);
|
||||
set_te64(&shdr->sh_addr, asl_delta + addr);
|
||||
}
|
||||
if (Elf64_Shdr::SHT_RELA == sh_type) {
|
||||
if (sizeof(Elf64_Rela) != sh_entsize) {
|
||||
char msg[50];
|
||||
snprintf(msg, sizeof(msg), "bad Rela.sh_entsize %lu", (long)sh_entsize);
|
||||
throwCantPack(msg);
|
||||
}
|
||||
n_jmp_slot = 0;
|
||||
plt_off = ~0ull;
|
||||
Elf64_Rela *rela = (Elf64_Rela *)(sh_offset + file_image);
|
||||
for (int k = sh_size / sh_entsize; --k >= 0; ++rela) {
|
||||
upx_uint64_t r_addend = get_te64(&rela->r_addend);
|
||||
upx_uint64_t r_offset = get_te64(&rela->r_offset);
|
||||
upx_uint64_t r_info = get_te64(&rela->r_info);
|
||||
unsigned r_type = ELF64_R_TYPE(r_info);
|
||||
if (xct_off <= r_offset) {
|
||||
set_te64(&rela->r_offset, asl_delta + r_offset);
|
||||
}
|
||||
if (Elf64_Ehdr::EM_AARCH64 == e_machine) {
|
||||
if (R_AARCH64_RELATIVE == r_type) {
|
||||
if (xct_off <= r_addend) {
|
||||
set_te64(&rela->r_addend, asl_delta + r_addend);
|
||||
}
|
||||
}
|
||||
if (R_AARCH64_JUMP_SLOT == r_type) {
|
||||
// .rela.plt contains offset of the "first time" target
|
||||
if (plt_off > (asl_delta + r_offset)) {
|
||||
plt_off = (asl_delta + r_offset);
|
||||
}
|
||||
upx_uint64_t d = elf_get_offset_from_address(asl_delta + r_offset);
|
||||
upx_uint64_t w = get_te64(&file_image[d]);
|
||||
if (xct_off <= w) {
|
||||
set_te64(&file_image[d], asl_delta + w);
|
||||
}
|
||||
++n_jmp_slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
fo->seek(sh_offset, SEEK_SET);
|
||||
fo->rewrite(sh_offset + file_image, sh_size);
|
||||
}
|
||||
if (Elf64_Shdr::SHT_REL == sh_type) {
|
||||
if (sizeof(Elf64_Rel) != sh_entsize) {
|
||||
char msg[50];
|
||||
snprintf(msg, sizeof(msg), "bad Rel.sh_entsize %lu", (long)sh_entsize);
|
||||
throwCantPack(msg);
|
||||
}
|
||||
Elf64_Rel *rel = (Elf64_Rel *)(sh_offset + file_image);
|
||||
for (int k = sh_size / sh_entsize; --k >= 0; ++rel) {
|
||||
upx_uint64_t r_offset = get_te64(&rel->r_offset);
|
||||
if (xct_off <= r_offset) {
|
||||
set_te64(&rel->r_offset, asl_delta + r_offset);
|
||||
}
|
||||
// r_offset must be in 2nd PT_LOAD; .p_vaddr was already relocated
|
||||
upx_uint64_t d = elf_get_offset_from_address(asl_delta + r_offset);
|
||||
upx_uint64_t w = get_te64(&file_image[d]);
|
||||
upx_uint64_t r_info = get_te32(&rel->r_info);
|
||||
unsigned r_type = ELF64_R_TYPE(r_info);
|
||||
if (xct_off <= w
|
||||
&& Elf64_Ehdr::EM_AARCH64 == e_machine
|
||||
&& ( R_AARCH64_RELATIVE == r_type
|
||||
|| R_AARCH64_JUMP_SLOT == r_type)) {
|
||||
set_te64(&file_image[d], asl_delta + w);
|
||||
}
|
||||
}
|
||||
fo->seek(sh_offset, SEEK_SET);
|
||||
fo->rewrite(sh_offset + file_image, sh_size);
|
||||
}
|
||||
}
|
||||
|
||||
// New copy of Shdr
|
||||
set_te64(&sec_strndx->sh_offset, (e_shnum * sizeof(Elf64_Shdr)) + sz_elf_hdrs);
|
||||
fo->seek(xct_off, SEEK_SET); fo->write(shdri, e_shnum * sizeof(Elf64_Shdr));
|
||||
|
||||
// New copy of Shdr[.e_shstrndx].[ sh_offset, +.sh_size )
|
||||
fo->write(shstrtab, sz_shstrtab);
|
||||
|
||||
sz_elf_hdrs = fpad4(fo);
|
||||
//xct_off += asl_delta; // wait until ::pack3
|
||||
}
|
||||
memset(&linfo, 0, sizeof(linfo));
|
||||
fo->write(&linfo, sizeof(linfo));
|
||||
}
|
||||
@@ -2667,27 +3016,12 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
// only execute if option present
|
||||
if (opt->o_unix.preserve_build_id) {
|
||||
// set this so we can use elf_find_section_name
|
||||
e_shnum = ehdri.e_shnum;
|
||||
|
||||
// there is a class member similar to this, but I did not
|
||||
// want to assume it would be available
|
||||
Elf64_Shdr const *tmp = shdri;
|
||||
|
||||
Elf64_Shdr *shdr = NULL;
|
||||
|
||||
if (! shdri) {
|
||||
shdr = New(Elf64_Shdr, e_shnum);
|
||||
|
||||
fi->seek(0,SEEK_SET);
|
||||
fi->seek(ehdri.e_shoff,SEEK_SET);
|
||||
fi->readx((void*)shdr,ehdri.e_shentsize*ehdri.e_shnum);
|
||||
|
||||
// set this so we can use elf_find_section_name
|
||||
shdri = (Elf64_Shdr *)shdr;
|
||||
e_shnum = get_te16(&ehdri.e_shnum);
|
||||
if (!shdri) {
|
||||
shdri = (Elf64_Shdr *)&file_image[get_te32(&ehdri.e_shoff)];
|
||||
}
|
||||
|
||||
//set the shstrtab
|
||||
sec_strndx = &shdri[ehdri.e_shstrndx];
|
||||
sec_strndx = &shdri[get_te16(&ehdri.e_shstrndx)];
|
||||
|
||||
char *strtab = New(char, sec_strndx->sh_size);
|
||||
fi->seek(0,SEEK_SET);
|
||||
@@ -2710,20 +3044,14 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
|
||||
memset(&shdrout,0,sizeof(shdrout));
|
||||
|
||||
//setup the build-id
|
||||
memcpy(&shdrout.shdr[1],buildid, sizeof(shdrout.shdr[1]));
|
||||
memcpy(&shdrout.shdr[1], buildid, sizeof(shdrout.shdr[1]));
|
||||
shdrout.shdr[1].sh_name = 1;
|
||||
|
||||
//setup the shstrtab
|
||||
memcpy(&shdrout.shdr[2],sec_strndx, sizeof(shdrout.shdr[2]));
|
||||
memcpy(&shdrout.shdr[2], sec_strndx, sizeof(shdrout.shdr[2]));
|
||||
shdrout.shdr[2].sh_name = 20;
|
||||
shdrout.shdr[2].sh_size = 29; //size of our static shstrtab
|
||||
}
|
||||
|
||||
if (shdr) {
|
||||
shdri = tmp;
|
||||
delete [] shdr;
|
||||
shdr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2822,7 +3150,7 @@ int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
|
||||
? (sizeof(Elf32_Ehdr) + sz_phdrs) // main executable
|
||||
: xct_off; // shared library
|
||||
if (ft.id < 0x40) {
|
||||
// FIXME: ?? ft.addvalue += delta;
|
||||
// FIXME: ?? ft.addvalue += asl_delta;
|
||||
}
|
||||
x.offset += delta;
|
||||
x.size -= delta;
|
||||
@@ -2931,7 +3259,7 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
|
||||
? (sizeof(Elf64_Ehdr) + sz_phdrs) // main executable
|
||||
: xct_off; // shared library
|
||||
if (ft.id < 0x40) {
|
||||
// FIXME: ?? ft.addvalue += delta;
|
||||
// FIXME: ?? ft.addvalue += asl_delta;
|
||||
}
|
||||
x.offset += delta;
|
||||
x.size -= delta;
|
||||
@@ -3096,82 +3424,6 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
||||
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
||||
}
|
||||
|
||||
if (0!=xct_off) { // shared library
|
||||
if (opt->o_unix.android_shlib && shdri) { // dlopen() checks Elf32_Shdr vs Elf32_Phdr
|
||||
unsigned load0_hi = ~0u;
|
||||
Elf32_Phdr const *phdr = phdri;
|
||||
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
|
||||
unsigned load0_lo = get_te32(&phdr->p_vaddr);
|
||||
unsigned load0_sz = get_te32(&phdr->p_memsz);
|
||||
if (PT_LOAD32==get_te32(&phdr->p_type)
|
||||
&& (xct_off - load0_lo) < load0_sz) {
|
||||
load0_hi = load0_lo + load0_sz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MemBuffer smap(e_shnum); smap.clear(); // smap[0] = 0; // SHN_UNDEF
|
||||
MemBuffer snew(e_shnum * sizeof(*shdri));
|
||||
Elf32_Shdr const *shdr = shdri;
|
||||
unsigned k = 0;
|
||||
for (unsigned j = 0; j < e_shnum; ++j, ++shdr) {
|
||||
// Select some Elf32_Shdr by .sh_type
|
||||
unsigned const type = get_te32(&shdr->sh_type);
|
||||
unsigned const flags = get_te32(&shdr->sh_flags);
|
||||
if (((Elf32_Shdr::SHT_STRTAB == type) && (Elf32_Shdr::SHF_ALLOC & flags))
|
||||
|| ((Elf32_Shdr::SHT_DYNAMIC == type) && (Elf32_Shdr::SHF_ALLOC & flags))
|
||||
|| ((Elf32_Shdr::SHT_ARM_ATTRIBUTES == type))
|
||||
|| ( ((1+ Elf32_Shdr::SHT_LOOS) <= type) // SHT_ANDROID_REL
|
||||
&& ((2+ Elf32_Shdr::SHT_LOOS) >= type)) // SHT_ANDROID_RELA
|
||||
) {
|
||||
Elf32_Shdr *const sptr = k + (Elf32_Shdr *)(void *)snew;
|
||||
unsigned va = get_te32(&shdr->sh_addr);
|
||||
if (xct_off <= va && va <= load0_hi) {
|
||||
throwCantPack("Android-required Shdr in packed region");
|
||||
}
|
||||
*sptr = *shdr; // copy old Elf32_Shdr
|
||||
smap[j] = 1+ k++; // for later forwarding
|
||||
}
|
||||
}
|
||||
if (k && fo) {
|
||||
unsigned const new_shoff = fpad4(fo);
|
||||
unsigned xtra_off = ((1+ k) * sizeof(*shdri)) + new_shoff; // 1+: shdr_undef
|
||||
set_te32(&ehdri.e_shoff, new_shoff);
|
||||
set_te16(&ehdri.e_shentsize, sizeof(*shdri));
|
||||
set_te16(&ehdri.e_shnum, 1+ k);
|
||||
Elf32_Shdr shdr_undef; memset(&shdr_undef, 0, sizeof(shdr_undef));
|
||||
fo->write(&shdr_undef, sizeof(shdr_undef));
|
||||
|
||||
unsigned arm_attr_offset = 0;
|
||||
unsigned arm_attr_size = 0;
|
||||
for (unsigned j = 0; j < k; ++j) { // forward .sh_link
|
||||
Elf32_Shdr *const sptr = j + (Elf32_Shdr *)(void *)snew;
|
||||
unsigned const type = get_te32(&sptr->sh_type);
|
||||
// work-around for https://bugs.launchpad.net/bugs/1712938
|
||||
if (Elf32_Shdr::SHT_ARM_ATTRIBUTES == type) {
|
||||
arm_attr_offset = get_te32(&sptr->sh_offset);
|
||||
arm_attr_size = get_te32(&sptr->sh_size);
|
||||
set_te32(&sptr->sh_offset, xtra_off);
|
||||
xtra_off += get_te32(&sptr->sh_size);
|
||||
}
|
||||
if (Elf32_Shdr::SHT_STRTAB == type) { // any SHT_STRTAB should work
|
||||
set_te16(&elfout.ehdr.e_shstrndx, 1+ j); // 1+: shdr_undef
|
||||
set_te16( &ehdri.e_shstrndx, 1+ j); // 1+: shdr_undef
|
||||
}
|
||||
unsigned sh_offset = get_te32(&sptr->sh_offset);
|
||||
if (xct_off <= sh_offset) {
|
||||
set_te32(&sptr->sh_offset, so_slide + sh_offset);
|
||||
}
|
||||
sptr->sh_name = 0; // we flushed .e_shstrndx
|
||||
set_te16(&sptr->sh_link, smap[sptr->sh_link]);
|
||||
set_te16(&sptr->sh_info, smap[sptr->sh_info]); // ?
|
||||
}
|
||||
fo->write(snew, k * sizeof(*shdri));
|
||||
if (arm_attr_offset) {
|
||||
fo->write(&file_image[arm_attr_offset], arm_attr_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
@@ -3234,82 +3486,6 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
||||
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
||||
}
|
||||
|
||||
if (0!=xct_off) { // shared library
|
||||
if (opt->o_unix.android_shlib && shdri) { // dlopen() checks Elf64_Shdr vs Elf64_Phdr
|
||||
unsigned load0_hi = ~0u;
|
||||
Elf64_Phdr const *phdr = phdri;
|
||||
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
|
||||
upx_uint64_t load0_lo = get_te64(&phdr->p_vaddr);
|
||||
upx_uint64_t load0_sz = get_te64(&phdr->p_memsz);
|
||||
if (PT_LOAD64==get_te32(&phdr->p_type)
|
||||
&& (xct_off - load0_lo) < load0_sz) {
|
||||
load0_hi = load0_lo + load0_sz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MemBuffer smap(e_shnum); smap.clear(); // smap[0] = 0; // SHN_UNDEF
|
||||
MemBuffer snew(e_shnum * sizeof(*shdri));
|
||||
Elf64_Shdr const *shdr = shdri;
|
||||
unsigned k = 0;
|
||||
for (unsigned j = 0; j < e_shnum; ++j, ++shdr) {
|
||||
// Select some Elf64_Shdr by .sh_type
|
||||
unsigned const type = get_te32(&shdr->sh_type);
|
||||
unsigned const flags = get_te32(&shdr->sh_flags);
|
||||
if (((Elf64_Shdr::SHT_STRTAB == type) && (Elf64_Shdr::SHF_ALLOC & flags))
|
||||
|| ((Elf64_Shdr::SHT_DYNAMIC == type) && (Elf64_Shdr::SHF_ALLOC & flags))
|
||||
|| ((Elf64_Shdr::SHT_ARM_ATTRIBUTES == type))
|
||||
|| ( ((1+ Elf64_Shdr::SHT_LOOS) <= type) // SHT_ANDROID_REL
|
||||
&& ((2+ Elf64_Shdr::SHT_LOOS) >= type)) // SHT_ANDROID_RELA
|
||||
) {
|
||||
Elf64_Shdr *const sptr = k + (Elf64_Shdr *)(void *)snew;
|
||||
upx_uint64_t va = get_te64(&shdr->sh_addr);
|
||||
if (xct_off <= va && va <= load0_hi) {
|
||||
throwCantPack("Android-required Shdr in packed region");
|
||||
}
|
||||
*sptr = *shdr; // copy old Elf64_Shdr
|
||||
smap[j] = 1+ k++; // for later forwarding
|
||||
}
|
||||
}
|
||||
if (k && fo) {
|
||||
unsigned long const new_shoff = fpad8(fo);
|
||||
unsigned long xtra_off = ((1+ k) * sizeof(*shdri)) + new_shoff; // 1+: shdr_undef
|
||||
set_te64(&ehdri.e_shoff, new_shoff);
|
||||
set_te16(&ehdri.e_shentsize, sizeof(*shdri));
|
||||
set_te16(&ehdri.e_shnum, 1+ k);
|
||||
Elf64_Shdr shdr_undef; memset(&shdr_undef, 0, sizeof(shdr_undef));
|
||||
fo->write(&shdr_undef, sizeof(shdr_undef));
|
||||
|
||||
unsigned long arm_attr_offset = 0;
|
||||
unsigned long arm_attr_size = 0;
|
||||
for (unsigned j = 0; j < k; ++j) { // forward .sh_link
|
||||
Elf64_Shdr *const sptr = j + (Elf64_Shdr *)(void *)snew;
|
||||
unsigned const type = get_te32(&sptr->sh_type);
|
||||
// work-around for https://bugs.launchpad.net/bugs/1712938
|
||||
if (Elf64_Shdr::SHT_ARM_ATTRIBUTES == type) {
|
||||
arm_attr_offset = get_te64(&sptr->sh_offset);
|
||||
arm_attr_size = get_te64(&sptr->sh_size);
|
||||
set_te64(&sptr->sh_offset, xtra_off);
|
||||
xtra_off += get_te64(&sptr->sh_size);
|
||||
}
|
||||
if (Elf64_Shdr::SHT_STRTAB == type) { // any SHT_STRTAB should work
|
||||
set_te16(&elfout.ehdr.e_shstrndx, 1+ j); // 1+: shdr_undef
|
||||
set_te16( &ehdri.e_shstrndx, 1+ j); // 1+: shdr_undef
|
||||
}
|
||||
upx_uint64_t sh_offset = get_te64(&sptr->sh_offset);
|
||||
if (xct_off <= sh_offset) {
|
||||
set_te64(&sptr->sh_offset, so_slide + sh_offset);
|
||||
}
|
||||
sptr->sh_name = 0; // we flushed .e_shstrndx
|
||||
set_te16(&sptr->sh_link, smap[sptr->sh_link]);
|
||||
set_te16(&sptr->sh_info, smap[sptr->sh_info]); // ?
|
||||
}
|
||||
fo->write(snew, k * sizeof(*shdri));
|
||||
if (arm_attr_offset) {
|
||||
fo->write(&file_image[arm_attr_offset], arm_attr_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
@@ -3321,7 +3497,7 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
||||
if (0!=xct_off) { // shared library
|
||||
fo->rewrite(&ehdri, sizeof(ehdri));
|
||||
fo->rewrite(phdri, e_phnum * sizeof(*phdri));
|
||||
fo->seek(xct_off, SEEK_SET);
|
||||
fo->seek(sz_elf_hdrs, SEEK_SET);
|
||||
fo->rewrite(&linfo, sizeof(linfo));
|
||||
}
|
||||
else {
|
||||
@@ -3865,7 +4041,7 @@ PackLinuxElf64::elf_find_dynamic(unsigned int key) const
|
||||
&& Elf64_Dyn::DT_NULL!=dynp->d_tag; ++dynp) if (get_te64(&dynp->d_tag)==key) {
|
||||
upx_uint64_t const t= elf_get_offset_from_address(get_te64(&dynp->d_val));
|
||||
if (t) {
|
||||
return (size_t)t + file_image;
|
||||
return &((unsigned char const *)file_image)[(size_t)t];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user