mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
Android shlib: work in progress
modified: p_lx_elf.cpp modified: p_lx_elf.h
This commit is contained in:
parent
edde6210f1
commit
f5fd94e815
172
src/p_lx_elf.cpp
172
src/p_lx_elf.cpp
|
@ -268,8 +268,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);
|
||||
|
@ -559,9 +559,11 @@ off_t PackLinuxElf64::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) {
|
||||
ehdri.e_shnum = 0;
|
||||
ehdri.e_shoff = 0;
|
||||
ehdri.e_shstrndx = 0;
|
||||
}
|
||||
}
|
||||
return flen;
|
||||
}
|
||||
|
@ -703,8 +705,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 +1720,29 @@ 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;
|
||||
|
||||
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,15 +1922,21 @@ 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_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)
|
||||
if (Elf64_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) {
|
||||
|
@ -1945,9 +1975,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
|
||||
uint64_t const strsz = elf_unsigned_dynamic(Elf64_Dyn::DT_STRSZ);
|
||||
uint64_t const strtab = elf_unsigned_dynamic(Elf64_Dyn::DT_STRTAB);
|
||||
uint64_t const relsz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELSZ);
|
||||
uint64_t const rel = elf_unsigned_dynamic(Elf64_Dyn::DT_REL);
|
||||
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.
|
||||
|
@ -2463,7 +2507,7 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
|||
if (opt->o_unix.preserve_build_id) {
|
||||
Elf32_Shdr *shdr = NULL;
|
||||
|
||||
Elf32_Shdr const *tmp = shdri;
|
||||
Elf32_Shdr *tmp = shdri;
|
||||
|
||||
if (! shdri) {
|
||||
shdr = New(Elf32_Shdr, e_shnum);
|
||||
|
@ -2477,7 +2521,7 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/)
|
|||
}
|
||||
|
||||
//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,11 +2544,11 @@ 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
|
||||
}
|
||||
|
@ -2620,7 +2664,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 +2699,79 @@ 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); // all before the first SHF_EXECINSTR (typ ".plt")
|
||||
if (opt->o_unix.android_shlib) {
|
||||
// In order to pacify the runtime linker on Android "O",
|
||||
// we splice-in a 4KiB page that contains an "extra" copy
|
||||
// of the Shdr and shstrtab.
|
||||
set_te64(&ehdri.e_shoff, sz_elf_hdrs);
|
||||
fo->seek(0, SEEK_SET); fo->rewrite(&ehdri, sizeof(ehdri));
|
||||
|
||||
unsigned const delta = (1u<<12);
|
||||
// Relocate Phdr
|
||||
phdr = phdri;
|
||||
for (int j = e_phnum; --j>=0; ++phdr) {
|
||||
uint64_t offset = get_te64(&phdr->p_offset);
|
||||
if (xct_off <= offset) {
|
||||
set_te64(&phdr->p_offset, delta + offset);
|
||||
uint64_t addr = get_te64(&phdr->p_paddr);
|
||||
set_te64(&phdr->p_paddr, delta + addr);
|
||||
addr = get_te64(&phdr->p_vaddr);
|
||||
set_te64(&phdr->p_vaddr, delta + addr);
|
||||
}
|
||||
if (0==phdr->p_offset && Elf64_Phdr::PT_LOAD==get_te32(&phdr->p_type)) {
|
||||
uint64_t size = get_te64(&phdr->p_filesz);
|
||||
set_te64(&phdr->p_filesz, delta + size);
|
||||
size = get_te64(&phdr->p_memsz);
|
||||
set_te64(&phdr->p_memsz, delta + size);
|
||||
}
|
||||
}
|
||||
fo->rewrite(phdri, e_phnum * sizeof(Elf64_Phdr));
|
||||
|
||||
// Relocate dynsym (DT_SYMTAB)
|
||||
Elf64_Sym *sym = const_cast<Elf64_Sym *>(dynsym);
|
||||
uint64_t off_dynsym = get_te64(&sec_dynsym->sh_offset);
|
||||
uint64_t sz_dynsym = get_te64(&sec_dynsym->sh_size);
|
||||
for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) {
|
||||
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, delta + symval);
|
||||
}
|
||||
}
|
||||
fo->seek(off_dynsym, SEEK_CUR); fo->rewrite(dynsym, sz_dynsym);
|
||||
|
||||
// FIXME?: Relocate contents of PT_DYNAMIC ?
|
||||
// Important stuff should be below xct_off
|
||||
|
||||
// FIXME: Relocate Elf64_Rela.r_offset
|
||||
|
||||
// New copy of Shdr, and relocated
|
||||
Elf64_Shdr *shdr = shdri;
|
||||
uint64_t sz_shstrtab = get_te64(&sec_strndx->sh_size);
|
||||
for (int j = e_shnum; --j>=0; ++shdr) {
|
||||
uint64_t offset = get_te64(&shdr->sh_offset);
|
||||
if (xct_off <= offset) {
|
||||
set_te64(&shdr->sh_offset, delta + offset);
|
||||
uint64_t addr = get_te64(&shdr->sh_addr);
|
||||
set_te64(&shdr->sh_addr, delta + addr);
|
||||
}
|
||||
}
|
||||
set_te64(&sec_strndx->sh_offset, (e_shnum * sizeof(Elf64_Shdr)) + sz_elf_hdrs);
|
||||
fo->seek(0, SEEK_END); fo->write(shdri, e_shnum * sizeof(Elf64_Shdr));
|
||||
|
||||
// New copy of Shdr[.e_shstrndx].[ sh_offset, +.sh_size )
|
||||
fo->write(shstrtab, sz_shstrtab);
|
||||
MemBuffer spacer(delta - (sz_shstrtab + e_shnum * sizeof(Elf64_Shdr)));
|
||||
spacer.clear();
|
||||
fo->write(spacer, spacer.getSize());
|
||||
sz_elf_hdrs += delta;
|
||||
xct_va += delta;
|
||||
xct_off += delta;
|
||||
}
|
||||
memset(&linfo, 0, sizeof(linfo));
|
||||
fo->write(&linfo, sizeof(linfo));
|
||||
}
|
||||
|
@ -2667,11 +2779,11 @@ 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;
|
||||
e_shnum = get_te16(&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 *tmp = shdri;
|
||||
|
||||
Elf64_Shdr *shdr = NULL;
|
||||
|
||||
|
@ -2687,7 +2799,7 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
|
|||
}
|
||||
|
||||
//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,11 +2822,11 @@ 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
|
||||
}
|
||||
|
@ -3235,7 +3347,7 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft)
|
|||
}
|
||||
|
||||
if (0!=xct_off) { // shared library
|
||||
if (opt->o_unix.android_shlib && shdri) { // dlopen() checks Elf64_Shdr vs Elf64_Phdr
|
||||
if (0 && 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) {
|
||||
|
@ -3865,7 +3977,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;
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ protected:
|
|||
protected:
|
||||
Elf32_Ehdr ehdri; // from input file
|
||||
Elf32_Phdr *phdri; // for input file
|
||||
Elf32_Shdr const *shdri; // from input file
|
||||
Elf32_Shdr *shdri; // from input file
|
||||
Elf32_Phdr const *gnu_stack; // propagate NX
|
||||
unsigned e_phoff;
|
||||
unsigned e_shoff;
|
||||
|
@ -282,7 +282,7 @@ protected:
|
|||
protected:
|
||||
Elf64_Ehdr ehdri; // from input file
|
||||
Elf64_Phdr *phdri; // for input file
|
||||
Elf64_Shdr const *shdri; // from input file
|
||||
Elf64_Shdr *shdri; // from input file
|
||||
Elf64_Phdr const *gnu_stack; // propagate NX
|
||||
upx_uint64_t e_phoff;
|
||||
upx_uint64_t e_shoff;
|
||||
|
@ -299,7 +299,7 @@ protected:
|
|||
Elf64_Sym const *jni_onload_sym;
|
||||
char const *shstrtab; // via Elf64_Shdr
|
||||
|
||||
Elf64_Shdr const *sec_strndx;
|
||||
Elf64_Shdr *sec_strndx;
|
||||
Elf64_Shdr const *sec_dynsym;
|
||||
Elf64_Shdr const *sec_dynstr;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user