Fix de-comression of shared libraries
modified: p_elf_enum.h modified: p_lx_elf.cpp modified: p_lx_elf.h
This commit is contained in:
@@ -74,7 +74,9 @@
|
|||||||
EM_PPC64 = 21,
|
EM_PPC64 = 21,
|
||||||
EM_ARM = 40,
|
EM_ARM = 40,
|
||||||
EM_X86_64 = 62,
|
EM_X86_64 = 62,
|
||||||
|
EM_AMD64 = EM_X86_64,
|
||||||
EM_AARCH64 = 183,
|
EM_AARCH64 = 183,
|
||||||
|
EM_ARM64 = EM_AARCH64,
|
||||||
|
|
||||||
};
|
};
|
||||||
enum { // e_version
|
enum { // e_version
|
||||||
@@ -260,6 +262,7 @@
|
|||||||
R_ARM_GLOB_DAT = 21,
|
R_ARM_GLOB_DAT = 21,
|
||||||
|
|
||||||
R_386_GLOB_DAT = 6,
|
R_386_GLOB_DAT = 6,
|
||||||
|
R_X86_64_64 = 1,
|
||||||
R_AARCH64_ABS64 = 257,
|
R_AARCH64_ABS64 = 257,
|
||||||
R_AARCH64_GLOB_DAT = 1025,
|
R_AARCH64_GLOB_DAT = 1025,
|
||||||
|
|
||||||
|
|||||||
+344
-107
@@ -442,8 +442,8 @@ PackLinuxElf32::elf_find_Phdr_for_va(upx_uint32_t addr, Elf32_Phdr const *phdr,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elf64_Phdr *
|
Elf64_Phdr const *
|
||||||
PackLinuxElf64::elf_find_Phdr_for_va(upx_uint64_t addr, Elf64_Phdr *phdr, unsigned phnum)
|
PackLinuxElf64::elf_find_Phdr_for_va(upx_uint64_t addr, Elf64_Phdr const *phdr, unsigned phnum)
|
||||||
{
|
{
|
||||||
for (unsigned j = 0; j < phnum; ++phdr) {
|
for (unsigned j = 0; j < phnum; ++phdr) {
|
||||||
if ((addr - get_te64(&phdr->p_vaddr)) < get_te64(&phdr->p_filesz)) {
|
if ((addr - get_te64(&phdr->p_vaddr)) < get_te64(&phdr->p_filesz)) {
|
||||||
@@ -529,8 +529,10 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
|
|||||||
unsigned const cpr_entry = (Elf32_Ehdr::EM_ARM==e_machine) + load_va + sz_pack2; // Thumb mode
|
unsigned const cpr_entry = (Elf32_Ehdr::EM_ARM==e_machine) + load_va + sz_pack2; // Thumb mode
|
||||||
set_te32(&file_image[user_init_off], cpr_entry); // set the hook
|
set_te32(&file_image[user_init_off], cpr_entry); // set the hook
|
||||||
|
|
||||||
Elf32_Dyn *dynp = (Elf32_Dyn *)elf_find_dynptr(Elf32_Dyn::DT_NULL); // for decompressor
|
if (user_init_rp) { // decompressor needs hint for DT_INIT_ARRAY
|
||||||
set_te32(&dynp->d_val, (char *)user_init_rp - (char *)&file_image[0]);
|
Elf32_Dyn *dynp = (Elf32_Dyn *)elf_find_dynptr(Elf32_Dyn::DT_NULL);
|
||||||
|
set_te32(&dynp->d_val, (char *)user_init_rp - (char *)&file_image[0]);
|
||||||
|
}
|
||||||
|
|
||||||
Elf32_Phdr *const phdr0 = (Elf32_Phdr *)lowmem.subref(
|
Elf32_Phdr *const phdr0 = (Elf32_Phdr *)lowmem.subref(
|
||||||
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf32_Phdr));
|
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf32_Phdr));
|
||||||
@@ -684,12 +686,12 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
total_out = fpad4(fo, total_out);
|
total_out = fpad4(fo, total_out);
|
||||||
|
|
||||||
if (0==xct_off) { // not shared library
|
if (0==xct_off) { // not shared library
|
||||||
set_te64(&elfout.phdr[C_BASE].p_align, ((upx_uint64_t)0) - page_mask);
|
set_te64(&elfout.phdr[C_BASE].p_align, ((u64_t)0) - page_mask);
|
||||||
elfout.phdr[C_BASE].p_paddr = elfout.phdr[C_BASE].p_vaddr;
|
elfout.phdr[C_BASE].p_paddr = elfout.phdr[C_BASE].p_vaddr;
|
||||||
elfout.phdr[C_BASE].p_offset = 0;
|
elfout.phdr[C_BASE].p_offset = 0;
|
||||||
upx_uint64_t abrk = getbrk(phdri, e_phnum);
|
u64_t abrk = getbrk(phdri, e_phnum);
|
||||||
// vbase handles ET_EXEC. FIXME: pre-linking?
|
// vbase handles ET_EXEC. FIXME: pre-linking?
|
||||||
upx_uint64_t const vbase = get_te64(&elfout.phdr[C_BASE].p_vaddr);
|
u64_t const vbase = get_te64(&elfout.phdr[C_BASE].p_vaddr);
|
||||||
set_te64(&elfout.phdr[C_BASE].p_filesz, 0x1000); // Linux kernel SIGSEGV if (0==.p_filesz)
|
set_te64(&elfout.phdr[C_BASE].p_filesz, 0x1000); // Linux kernel SIGSEGV if (0==.p_filesz)
|
||||||
set_te64(&elfout.phdr[C_BASE].p_memsz, abrk - vbase);
|
set_te64(&elfout.phdr[C_BASE].p_memsz, abrk - vbase);
|
||||||
set_te64(&elfout.phdr[C_BASE].p_flags, Elf64_Phdr::PF_W|Elf64_Phdr::PF_R);
|
set_te64(&elfout.phdr[C_BASE].p_flags, Elf64_Phdr::PF_W|Elf64_Phdr::PF_R);
|
||||||
@@ -699,9 +701,14 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
elfout.phdr[C_TEXT].p_paddr = elfout.phdr[C_TEXT].p_vaddr;
|
elfout.phdr[C_TEXT].p_paddr = elfout.phdr[C_TEXT].p_vaddr;
|
||||||
set_te64(&elfout.ehdr.e_entry, abrk + get_te64(&elfout.ehdr.e_entry) - vbase);
|
set_te64(&elfout.ehdr.e_entry, abrk + get_te64(&elfout.ehdr.e_entry) - vbase);
|
||||||
}
|
}
|
||||||
if (0!=xct_off) { // shared library
|
if (0!=xct_off) { // shared library
|
||||||
upx_uint64_t word = load_va + sz_pack2;
|
u64_t const cpr_entry = (Elf64_Ehdr::EM_ARM==e_machine) + load_va + sz_pack2; // Thumb mode
|
||||||
set_te64(&file_image[user_init_off], word); // set the hook
|
set_te64(&file_image[user_init_off], cpr_entry); // set the hook
|
||||||
|
|
||||||
|
if (user_init_rp) { // decompressor needs hint for DT_INIT_ARRAY
|
||||||
|
Elf64_Dyn *dynp = (Elf64_Dyn *)elf_find_dynptr(Elf64_Dyn::DT_NULL);
|
||||||
|
set_te64(&dynp->d_val, (char *)user_init_rp - (char *)&file_image[0]);
|
||||||
|
}
|
||||||
|
|
||||||
Elf64_Phdr *const phdr0 = (Elf64_Phdr *)lowmem.subref(
|
Elf64_Phdr *const phdr0 = (Elf64_Phdr *)lowmem.subref(
|
||||||
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf64_Phdr));
|
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf64_Phdr));
|
||||||
@@ -710,9 +717,9 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
so_slide = 0;
|
so_slide = 0;
|
||||||
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
|
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
|
||||||
// p_vaddr and p_paddr do not change!
|
// p_vaddr and p_paddr do not change!
|
||||||
upx_uint64_t const len = get_te64(&phdr->p_filesz);
|
u64_t const len = get_te64(&phdr->p_filesz);
|
||||||
upx_uint64_t const ioff = get_te64(&phdri[j].p_offset); // without asl_delta
|
u64_t const ioff = get_te64(&phdri[j].p_offset); // without asl_delta
|
||||||
upx_uint64_t align= get_te64(&phdr->p_align);
|
u64_t align= get_te64(&phdr->p_align);
|
||||||
unsigned const type = get_te32(&phdr->p_type);
|
unsigned const type = get_te32(&phdr->p_type);
|
||||||
if (Elf64_Phdr::PT_INTERP==type) {
|
if (Elf64_Phdr::PT_INTERP==type) {
|
||||||
// Rotate to highest position, so it can be lopped
|
// Rotate to highest position, so it can be lopped
|
||||||
@@ -735,12 +742,12 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
set_te64(&phdr->p_memsz, total_out - ioff);
|
set_te64(&phdr->p_memsz, total_out - ioff);
|
||||||
if (user_init_off < xct_off) { // MIPS puts PT_DYNAMIC here
|
if (user_init_off < xct_off) { // MIPS puts PT_DYNAMIC here
|
||||||
// Allow for DT_INIT in a new [stolen] slot
|
// Allow for DT_INIT in a new [stolen] slot
|
||||||
unsigned off2 = user_init_off - sizeof(word);
|
unsigned off2 = user_init_off - sizeof(u64_t);
|
||||||
fo->seek(off2, SEEK_SET);
|
fo->seek(off2, SEEK_SET);
|
||||||
fo->rewrite(&file_image[off2], 2*sizeof(word));
|
fo->rewrite(&file_image[off2], 2*sizeof(u64_t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (xct_off < ioff) { // Slide subsequent PT_LOAD.
|
else if (xct_off < ioff) { // Slide subsequent PT_LOAD.
|
||||||
if ((1u<<12) < align
|
if ((1u<<12) < align
|
||||||
&& Elf64_Ehdr::EM_X86_64 == e_machine // FIXME: other $ARCH ?
|
&& Elf64_Ehdr::EM_X86_64 == e_machine // FIXME: other $ARCH ?
|
||||||
) {
|
) {
|
||||||
@@ -749,7 +756,7 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
}
|
}
|
||||||
off = fpadN(fo, (-1 + align) & (ioff - off));
|
off = fpadN(fo, (-1 + align) & (ioff - off));
|
||||||
if (!so_slide) {
|
if (!so_slide) {
|
||||||
so_slide = off - (asl_delta + ioff);
|
so_slide = off - ((is_asl ? asl_delta : 0) + ioff);
|
||||||
//asl_slide_Shdrs();
|
//asl_slide_Shdrs();
|
||||||
}
|
}
|
||||||
set_te64(&phdr->p_offset, off);
|
set_te64(&phdr->p_offset, off);
|
||||||
@@ -757,29 +764,28 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
fo->write(&file_image[ioff], len);
|
fo->write(&file_image[ioff], len);
|
||||||
off += len;
|
off += len;
|
||||||
total_out = off;
|
total_out = off;
|
||||||
|
|
||||||
|
if ((user_init_off - ioff) < len) {
|
||||||
|
fo->seek(user_init_off + so_slide, SEEK_SET);
|
||||||
|
u64_t word = cpr_entry;
|
||||||
|
set_te64(&word, cpr_entry);
|
||||||
|
fo->rewrite(&word, sizeof(word));
|
||||||
|
fo->seek(0, SEEK_END);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
continue; // all done with this PT_LOAD
|
continue; // all done with this PT_LOAD
|
||||||
}
|
}
|
||||||
if (xct_off < ioff) {
|
if (xct_off < ioff) {
|
||||||
set_te64(&phdr->p_offset, so_slide + asl_delta + ioff);
|
set_te64(&phdr->p_offset, so_slide + (is_asl ? asl_delta : 0) + ioff);
|
||||||
}
|
}
|
||||||
} // end each Phdr
|
} // end each Phdr
|
||||||
|
|
||||||
if (opt->o_unix.android_shlib) {
|
if (sec_arm_attr || is_asl) { // must update Shdr.sh_offset for so_slide
|
||||||
// Update {DYNAMIC}.sh_offset by so_slide.
|
// Update {DYNAMIC}.sh_offset by so_slide.
|
||||||
Elf64_Shdr *shdr = (Elf64_Shdr *)lowmem.subref(
|
Elf64_Shdr *shdr = (Elf64_Shdr *)lowmem.subref( // FIXME: use shdri ?
|
||||||
"bad e_shoff", xct_off - asl_delta, e_shnum * sizeof(Elf64_Shdr));
|
"bad e_shoff", xct_off - (is_asl ? asl_delta : 0), e_shnum * sizeof(Elf64_Shdr));
|
||||||
for (unsigned j = 0; j < e_shnum; ++shdr, ++j) {
|
for (unsigned j = 0; j < e_shnum; ++shdr, ++j) {
|
||||||
unsigned sh_type = get_te32(&shdr->sh_type);
|
unsigned sh_type = get_te32(&shdr->sh_type);
|
||||||
#if 0 //{ ? old 2018-01-15
|
|
||||||
if (Elf64_Shdr::SHT_DYNAMIC == sh_type) {
|
|
||||||
upx_uint64_t offset = get_te64(&shdr->sh_offset);
|
|
||||||
set_te64(&shdr->sh_offset, so_slide + offset);
|
|
||||||
fo->seek((j * sizeof(Elf64_Shdr)) + xct_off - asl_delta, SEEK_SET);
|
|
||||||
fo->rewrite(shdr, sizeof(*shdr));
|
|
||||||
fo->seek(0, SEEK_END);
|
|
||||||
}
|
|
||||||
#endif //}
|
|
||||||
unsigned sh_flags = get_te32(&shdr->sh_flags);
|
unsigned sh_flags = get_te32(&shdr->sh_flags);
|
||||||
unsigned sh_offset = get_te64(&shdr->sh_offset); // already asl_delta
|
unsigned sh_offset = get_te64(&shdr->sh_offset); // already asl_delta
|
||||||
if (Elf64_Shdr::SHF_ALLOC & sh_flags
|
if (Elf64_Shdr::SHF_ALLOC & sh_flags
|
||||||
@@ -790,32 +796,45 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
|
|||||||
if (Elf64_Shdr::SHT_RELA == sh_type
|
if (Elf64_Shdr::SHT_RELA == sh_type
|
||||||
&& n_jmp_slot // FIXME: does this apply to SHT_RELA ?
|
&& n_jmp_slot // FIXME: does this apply to SHT_RELA ?
|
||||||
&& !strcmp(".rel.plt", get_te32(&shdr->sh_name) + shstrtab)) {
|
&& !strcmp(".rel.plt", get_te32(&shdr->sh_name) + shstrtab)) {
|
||||||
upx_uint64_t va = elf_unsigned_dynamic(Elf64_Dyn::DT_PLTGOT) - asl_delta;
|
u64_t va = elf_unsigned_dynamic(Elf64_Dyn::DT_PLTGOT) - (is_asl ? asl_delta : 0);
|
||||||
// Now use the old Phdrs (phdri)
|
// Now use the old Phdrs (phdri)
|
||||||
Elf64_Phdr const *phva;
|
Elf64_Phdr const *phva;
|
||||||
phva = elf_find_Phdr_for_va(va, phdri, e_phnum);
|
phva = elf_find_Phdr_for_va(va, phdri, e_phnum);
|
||||||
upx_uint64_t old_off = (va - get_te64(&phva->p_vaddr))
|
u64_t old_off = (va - get_te64(&phva->p_vaddr))
|
||||||
+ get_te64(&phva->p_offset);
|
+ get_te64(&phva->p_offset);
|
||||||
|
|
||||||
// Now use the new Phdrs (phdr0)
|
// Now use the new Phdrs (phdr0)
|
||||||
va += asl_delta;
|
va += (is_asl ? asl_delta : 0);
|
||||||
phva = elf_find_Phdr_for_va(va, phdr0, e_phnum);
|
phva = elf_find_Phdr_for_va(va, phdr0, e_phnum);
|
||||||
upx_uint64_t new_off = (va - get_te64(&phva->p_vaddr))
|
u64_t new_off = (va - get_te64(&phva->p_vaddr))
|
||||||
+ get_te64(&phva->p_offset);
|
+ get_te64(&phva->p_offset);
|
||||||
|
|
||||||
if (fo) {
|
if (fo && n_jmp_slot) {
|
||||||
fo->seek(new_off, SEEK_SET);
|
fo->seek(new_off, SEEK_SET);
|
||||||
fo->rewrite(&file_image[old_off], n_jmp_slot * 8);
|
fo->rewrite(&file_image[old_off], n_jmp_slot * 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (j && shdr->sh_addr == 0
|
||||||
|
&& get_te32(&shdr->sh_offset) < xct_off) {
|
||||||
|
// Try to be nice by sliding; but still fails if compressed.
|
||||||
|
// So don't do it unless appending plain text of shstrtab.
|
||||||
|
unsigned sh_off = get_te32(&shdr->sh_offset);
|
||||||
|
if (xct_off < sh_off) {
|
||||||
|
set_te32(&shdr->sh_offset, sh_off + so_slide);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (fo) {
|
// Maybe: append plain text of shstrtab strings?
|
||||||
fo->seek((unsigned char *)shdro - (unsigned char *)(void *)lowmem, SEEK_SET);
|
fo->seek(total_out, SEEK_SET);
|
||||||
fo->rewrite(shdro, e_shnum * sizeof(*shdr));
|
if (xct_off < e_shoff) {
|
||||||
fo->seek(0, SEEK_END);
|
set_te32(&((Elf32_Ehdr *)lowmem.getVoidPtr())->e_shoff, total_out);
|
||||||
|
if (fo) {
|
||||||
|
fo->write(shdri, e_shnum * sizeof(*shdr));
|
||||||
|
total_out += e_shnum * sizeof(*shdr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // !opt->o_unix.android_shlib)
|
else { // output has no Shdr
|
||||||
ehdri.e_shnum = 0;
|
ehdri.e_shnum = 0;
|
||||||
ehdri.e_shoff = 0;
|
ehdri.e_shoff = 0;
|
||||||
ehdri.e_shstrndx = 0;
|
ehdri.e_shstrndx = 0;
|
||||||
@@ -909,6 +928,7 @@ PackLinuxElf64::PackLinuxElf64(InputFile *f)
|
|||||||
gashtab(nullptr), gashend(nullptr), dynsym(nullptr),
|
gashtab(nullptr), gashend(nullptr), dynsym(nullptr),
|
||||||
jni_onload_sym(nullptr),
|
jni_onload_sym(nullptr),
|
||||||
sec_strndx(nullptr), sec_dynsym(nullptr), sec_dynstr(nullptr)
|
sec_strndx(nullptr), sec_dynsym(nullptr), sec_dynstr(nullptr)
|
||||||
|
, sec_arm_attr(nullptr)
|
||||||
{
|
{
|
||||||
memset(&ehdri, 0, sizeof(ehdri));
|
memset(&ehdri, 0, sizeof(ehdri));
|
||||||
n_jmp_slot = 0;
|
n_jmp_slot = 0;
|
||||||
@@ -2775,6 +2795,13 @@ bad:
|
|||||||
// Take one as a last resort.
|
// Take one as a last resort.
|
||||||
if ((Elf32_Dyn::DT_INIT==upx_dt_init || !upx_dt_init)
|
if ((Elf32_Dyn::DT_INIT==upx_dt_init || !upx_dt_init)
|
||||||
&& Elf32_Shdr::SHT_DYNAMIC == sh_type) {
|
&& Elf32_Shdr::SHT_DYNAMIC == sh_type) {
|
||||||
|
unsigned sh_offset = get_te64(&shdr->sh_offset);
|
||||||
|
unsigned sh_size = get_te64(&shdr->sh_size);
|
||||||
|
if ((unsigned)file_size < sh_size
|
||||||
|
|| (unsigned)file_size < sh_offset
|
||||||
|
|| ((unsigned)file_size - sh_offset) < sh_size) {
|
||||||
|
throwCantPack("bad SHT_DYNAMIC");
|
||||||
|
}
|
||||||
unsigned const n = get_te32(&shdr->sh_size) / sizeof(Elf32_Dyn);
|
unsigned const n = get_te32(&shdr->sh_size) / sizeof(Elf32_Dyn);
|
||||||
Elf32_Dyn *dynp = (Elf32_Dyn *)&file_image[get_te32(&shdr->sh_offset)];
|
Elf32_Dyn *dynp = (Elf32_Dyn *)&file_image[get_te32(&shdr->sh_offset)];
|
||||||
for (; Elf32_Dyn::DT_NULL != dynp->d_tag; ++dynp) {
|
for (; Elf32_Dyn::DT_NULL != dynp->d_tag; ++dynp) {
|
||||||
@@ -3024,9 +3051,9 @@ PackLinuxElf64::canPack()
|
|||||||
invert_pt_dynamic(dynseg,
|
invert_pt_dynamic(dynseg,
|
||||||
umin(get_te64(&phdr->p_filesz), file_size - offset));
|
umin(get_te64(&phdr->p_filesz), file_size - offset));
|
||||||
}
|
}
|
||||||
else if (PT_LOAD64==get_te32(&phdr->p_type)) {
|
else if (is_LOAD64(phdr)) {
|
||||||
if (!pload_x0
|
if (!pload_x0
|
||||||
&& Elf32_Phdr::PF_X & get_te32(&phdr->p_flags)
|
&& Elf64_Phdr::PF_X & get_te32(&phdr->p_flags)
|
||||||
) {
|
) {
|
||||||
pload_x0 = phdr;
|
pload_x0 = phdr;
|
||||||
}
|
}
|
||||||
@@ -3088,10 +3115,11 @@ PackLinuxElf64::canPack()
|
|||||||
xct_va = umin(xct_va, get_te64(&shdr->sh_addr));
|
xct_va = umin(xct_va, get_te64(&shdr->sh_addr));
|
||||||
}
|
}
|
||||||
// Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY.
|
// Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY.
|
||||||
if (( Elf64_Dyn::DT_PREINIT_ARRAY==upx_dt_init
|
if (!user_init_rp && (
|
||||||
&& Elf64_Shdr::SHT_PREINIT_ARRAY==sh_type)
|
( Elf64_Dyn::DT_PREINIT_ARRAY==upx_dt_init
|
||||||
|| ( Elf64_Dyn::DT_INIT_ARRAY ==upx_dt_init
|
&& Elf64_Shdr::SHT_PREINIT_ARRAY==sh_type)
|
||||||
&& Elf64_Shdr::SHT_INIT_ARRAY ==sh_type) ) {
|
|| ( Elf64_Dyn::DT_INIT_ARRAY ==upx_dt_init
|
||||||
|
&& Elf64_Shdr::SHT_INIT_ARRAY ==sh_type) )) {
|
||||||
unsigned user_init_ava = get_te32(&shdr->sh_addr);
|
unsigned user_init_ava = get_te32(&shdr->sh_addr);
|
||||||
user_init_off = get_te64(&shdr->sh_offset);
|
user_init_off = get_te64(&shdr->sh_offset);
|
||||||
if ((u64_t)file_size <= user_init_off) {
|
if ((u64_t)file_size <= user_init_off) {
|
||||||
@@ -3101,8 +3129,8 @@ PackLinuxElf64::canPack()
|
|||||||
throwCantPack(msg);
|
throwCantPack(msg);
|
||||||
}
|
}
|
||||||
// Check that &file_image[user_init_off] has
|
// Check that &file_image[user_init_off] has
|
||||||
// *_RELATIVE relocation, and fetch user_init_va.
|
// *_RELATIVE or *_ABS* relocation, and fetch user_init_va.
|
||||||
// If Elf64_Rela then the actual value is in Rela.r_addend.
|
// If Elf_Rela then the actual value is in Rela.r_addend.
|
||||||
int z_rel = dt_table[Elf64_Dyn::DT_RELA];
|
int z_rel = dt_table[Elf64_Dyn::DT_RELA];
|
||||||
int z_rsz = dt_table[Elf64_Dyn::DT_RELASZ];
|
int z_rsz = dt_table[Elf64_Dyn::DT_RELASZ];
|
||||||
if (z_rel && z_rsz) {
|
if (z_rel && z_rsz) {
|
||||||
@@ -3125,6 +3153,7 @@ PackLinuxElf64::canPack()
|
|||||||
for (; rp < last; ++rp) {
|
for (; rp < last; ++rp) {
|
||||||
upx_uint64_t r_va = get_te64(&rp->r_offset);
|
upx_uint64_t r_va = get_te64(&rp->r_offset);
|
||||||
if (r_va == user_init_ava) { // found the Elf64_Rela
|
if (r_va == user_init_ava) { // found the Elf64_Rela
|
||||||
|
user_init_rp = rp;
|
||||||
upx_uint64_t r_info = get_te64(&rp->r_info);
|
upx_uint64_t r_info = get_te64(&rp->r_info);
|
||||||
unsigned r_type = ELF64_R_TYPE(r_info);
|
unsigned r_type = ELF64_R_TYPE(r_info);
|
||||||
if (Elf64_Ehdr::EM_AARCH64 == e_machine
|
if (Elf64_Ehdr::EM_AARCH64 == e_machine
|
||||||
@@ -4997,6 +5026,9 @@ int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
|
|||||||
|
|
||||||
x.offset = p_offset + hdr_u_len;
|
x.offset = p_offset + hdr_u_len;
|
||||||
x.size = p_filesz - hdr_u_len;
|
x.size = p_filesz - hdr_u_len;
|
||||||
|
|
||||||
|
Elf32_Phdr *phdr = k + (Elf32_Phdr *)(1+ (Elf32_Ehdr *)&lowmem[0]);
|
||||||
|
set_te32(&phdr->p_flags, Elf32_Phdr::PF_X | get_te32(&phdr->p_flags));
|
||||||
hdr_u_len = 0; // no longer the first time
|
hdr_u_len = 0; // no longer the first time
|
||||||
}
|
}
|
||||||
// The remainder above xct_off in first compressible PT_LOAD
|
// The remainder above xct_off in first compressible PT_LOAD
|
||||||
@@ -5204,14 +5236,26 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
|
|||||||
}
|
}
|
||||||
else { // Just copy up to xct_off
|
else { // Just copy up to xct_off
|
||||||
x.size = umin(x.size, xct_off - x.offset);
|
x.size = umin(x.size, xct_off - x.offset);
|
||||||
fi->seek(x.offset, SEEK_SET);
|
if (0) { // DEBUG paranoia
|
||||||
fi->readx(ibuf, x.size);
|
fi->seek(x.offset, SEEK_SET);
|
||||||
total_in += x.size;
|
fi->readx(ibuf, x.size);
|
||||||
|
total_in += x.size;
|
||||||
|
unsigned const *fip = (unsigned const *)file_image.getVoidPtr();
|
||||||
|
unsigned const *ibp = (unsigned const *)ibuf.getVoidPtr();
|
||||||
|
for (unsigned j = 0; j < x.size>>2; ++j) {
|
||||||
|
if (fip[j] != ibp[j]) {
|
||||||
|
printf("[%#x]: file_image %#x ibuf %#x\n", j, fip[j], ibp[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: adler2 ?
|
// FIXME: adler2 ?
|
||||||
fo->seek(x.offset, SEEK_SET);
|
fo->seek(x.offset, SEEK_SET);
|
||||||
fo->write(ibuf, x.size);
|
fo->write(&file_image[x.offset], x.size);
|
||||||
total_out += x.size;
|
total_out += x.size;
|
||||||
|
// Kepp the input side in sync
|
||||||
|
total_in += x.size;
|
||||||
|
fi->seek(x.size + x.offset, SEEK_SET);
|
||||||
}
|
}
|
||||||
if (hdr_u_len) { // first time
|
if (hdr_u_len) { // first time
|
||||||
linfo.l_checksum = 0; // preliminary
|
linfo.l_checksum = 0; // preliminary
|
||||||
@@ -5241,6 +5285,8 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
|
|||||||
x.offset = p_offset + hdr_u_len;
|
x.offset = p_offset + hdr_u_len;
|
||||||
x.size = p_filesz - hdr_u_len;
|
x.size = p_filesz - hdr_u_len;
|
||||||
|
|
||||||
|
Elf64_Phdr *phdr = k + (Elf64_Phdr *)(1+ (Elf64_Ehdr *)&lowmem[0]);
|
||||||
|
set_te32(&phdr->p_flags, Elf64_Phdr::PF_X | get_te32(&phdr->p_flags));
|
||||||
hdr_u_len = 0; // no longer the first time
|
hdr_u_len = 0; // no longer the first time
|
||||||
}
|
}
|
||||||
// The remainder above xct_off in first compressible PT_LOAD
|
// The remainder above xct_off in first compressible PT_LOAD
|
||||||
@@ -5431,29 +5477,8 @@ void PackLinuxElf32mipsel::defineSymbols(Filter const *ft)
|
|||||||
PackLinuxElf32::defineSymbols(ft);
|
PackLinuxElf32::defineSymbols(ft);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
void PackLinuxElf32::forward_Shdrs(OutputFile *fo)
|
||||||
{
|
{
|
||||||
if (!xct_off) {
|
|
||||||
overlay_offset = sz_elf_hdrs + sizeof(linfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt->o_unix.preserve_build_id) {
|
|
||||||
// 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(&elfout.ehdr.e_shoff,len);
|
|
||||||
|
|
||||||
int const ssize = sizeof(shdrout);
|
|
||||||
|
|
||||||
shdrout.shdr[2].sh_offset = len+ssize;
|
|
||||||
shdrout.shdr[1].sh_offset = shdrout.shdr[2].sh_offset+shdrout.shdr[2].sh_size;
|
|
||||||
|
|
||||||
fo->write(&shdrout, ssize);
|
|
||||||
|
|
||||||
fo->write(o_shstrtab,shdrout.shdr[2].sh_size);
|
|
||||||
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
|
||||||
}
|
|
||||||
if (saved_opt_android_shlib) { // Forward select _Shdr
|
if (saved_opt_android_shlib) { // Forward select _Shdr
|
||||||
// Keep _Shdr for rtld data (below xct_off).
|
// Keep _Shdr for rtld data (below xct_off).
|
||||||
// Discard _Shdr for compressed regions.
|
// Discard _Shdr for compressed regions.
|
||||||
@@ -5556,6 +5581,138 @@ void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
|||||||
fo->write(eho, sizeof(*eho));
|
fo->write(eho, sizeof(*eho));
|
||||||
fo->seek(0, SEEK_END);
|
fo->seek(0, SEEK_END);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackLinuxElf64::forward_Shdrs(OutputFile *fo)
|
||||||
|
{
|
||||||
|
if (saved_opt_android_shlib) { // Forward select _Shdr
|
||||||
|
// Keep _Shdr for rtld data (below xct_off).
|
||||||
|
// Discard _Shdr for compressed regions.
|
||||||
|
// Keep _Shdr for SHF_WRITE.
|
||||||
|
// Discard _Shdr with (0==sh_addr), except _Shdr[0]
|
||||||
|
// Keep ARM_ATTRIBUTES
|
||||||
|
Elf64_Ehdr *eho = (Elf64_Ehdr *)lowmem.getVoidPtr();
|
||||||
|
MemBuffer mb_ask_for(e_shnum * sizeof(eho->e_shnum));
|
||||||
|
memset(mb_ask_for, 0, mb_ask_for.getSize());
|
||||||
|
unsigned short *const ask_for = (unsigned short *)mb_ask_for.getVoidPtr();
|
||||||
|
|
||||||
|
MemBuffer mb_shdro(e_shnum * sizeof(*shdri));
|
||||||
|
Elf64_Shdr *sh_out0 = (Elf64_Shdr *)mb_shdro.getVoidPtr();
|
||||||
|
Elf64_Shdr *sh_out = sh_out0;
|
||||||
|
Elf64_Shdr *sh_in = shdri;
|
||||||
|
|
||||||
|
memset(sh_out, 0, sizeof(*sh_out)); // blank sh_out[0]
|
||||||
|
++sh_in; ++sh_out; unsigned n_sh_out = 1;
|
||||||
|
|
||||||
|
for (unsigned j = 1; j < e_shnum; ++j, ++sh_in) {
|
||||||
|
u64_t sh_offset = get_te64(&sh_in->sh_offset);
|
||||||
|
u64_t sh_flags = get_te64(&sh_in->sh_flags);
|
||||||
|
unsigned sh_info = get_te16(&sh_in->sh_info);
|
||||||
|
if (ask_for[j]) { // Some previous _Shdr requested me
|
||||||
|
// Tell them my new index
|
||||||
|
set_te16(&sh_out0[ask_for[j]].sh_info, n_sh_out);
|
||||||
|
}
|
||||||
|
ask_for[sh_info] = j; // Enter my request, if any
|
||||||
|
if ( (sh_offset && sh_offset < xct_off)
|
||||||
|
|| (Elf64_Shdr::SHF_WRITE & sh_flags)
|
||||||
|
|| (j == e_shstrndx)
|
||||||
|
|| (sec_arm_attr == sh_in)
|
||||||
|
) {
|
||||||
|
*sh_out = *sh_in;
|
||||||
|
if (sec_arm_attr == sh_in) {
|
||||||
|
set_te64(&sh_out->sh_offset, total_out);
|
||||||
|
fi->seek(get_te64(&sh_in->sh_offset), SEEK_SET);
|
||||||
|
u64_t len = get_te64(&sh_in->sh_size);
|
||||||
|
fi->read(ibuf, len);
|
||||||
|
fo->write(ibuf, len);
|
||||||
|
total_out += len;
|
||||||
|
}
|
||||||
|
if (j == e_shstrndx) {
|
||||||
|
set_te16(&eho->e_shstrndx, sh_out - (Elf64_Shdr *)mb_shdro.getVoidPtr());
|
||||||
|
set_te64(&sh_out->sh_offset, total_out);
|
||||||
|
fi->seek(get_te64(&sh_in->sh_offset), SEEK_SET);
|
||||||
|
u64_t len = get_te64(&sh_in->sh_size);
|
||||||
|
fi->read(ibuf, len);
|
||||||
|
fo->write(ibuf, len);
|
||||||
|
total_out += len;
|
||||||
|
}
|
||||||
|
if (Elf64_Shdr::SHF_WRITE & sh_flags) {
|
||||||
|
set_te64(&sh_out->sh_offset, so_slide + get_te64(&sh_out->sh_offset));
|
||||||
|
}
|
||||||
|
++sh_out; ++n_sh_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total_out = fpad4(fo, total_out);
|
||||||
|
set_te64(&eho->e_shoff, total_out);
|
||||||
|
unsigned len = (char *)sh_out - (char *)mb_shdro.getVoidPtr();
|
||||||
|
set_te16(&eho->e_shnum, len / sizeof(*sh_out));
|
||||||
|
fo->write(mb_shdro, len);
|
||||||
|
total_out += len;
|
||||||
|
fo->seek(0, SEEK_SET);
|
||||||
|
fo->write(eho, sizeof(*eho));
|
||||||
|
fo->seek(0, SEEK_END);
|
||||||
|
}
|
||||||
|
else if (sec_arm_attr) {
|
||||||
|
// Forward just ARM_ATTRIBUTES
|
||||||
|
Elf64_Shdr shdr_aa[3];
|
||||||
|
u64_t const attr_len = get_te64(&sec_arm_attr->sh_size);
|
||||||
|
char const str_aa[] = "\x00" ".shstrtab\x00" ".ARM.attributes\x00";
|
||||||
|
|
||||||
|
memset(shdr_aa, 0, sizeof shdr_aa);
|
||||||
|
// shstrtab
|
||||||
|
set_te64(&shdr_aa[1].sh_name, 1);
|
||||||
|
set_te64(&shdr_aa[1].sh_type, Elf64_Shdr::SHT_STRTAB);
|
||||||
|
set_te64(&shdr_aa[1].sh_offset, total_out);
|
||||||
|
set_te64(&shdr_aa[1].sh_size, sizeof(str_aa));
|
||||||
|
set_te64(&shdr_aa[1].sh_addralign, 1);
|
||||||
|
fo->write(str_aa, sizeof(str_aa)); total_out += sizeof(str_aa);
|
||||||
|
|
||||||
|
// ARM_ATTRIBUTES
|
||||||
|
set_te64(&shdr_aa[2].sh_name, 11);
|
||||||
|
set_te64(&shdr_aa[2].sh_type, Elf64_Shdr::SHT_ARM_ATTRIBUTES);
|
||||||
|
set_te64(&shdr_aa[2].sh_offset, total_out);
|
||||||
|
set_te64(&shdr_aa[2].sh_size, attr_len);
|
||||||
|
set_te64(&shdr_aa[2].sh_addralign, 1);
|
||||||
|
fo->write(&file_image[get_te64(&sec_arm_attr->sh_offset)], attr_len);
|
||||||
|
total_out = fpad4(fo, total_out += attr_len);
|
||||||
|
|
||||||
|
Elf64_Ehdr *eho = &elfout.ehdr;
|
||||||
|
set_te16(&eho->e_shnum, 3);
|
||||||
|
set_te64(&eho->e_shoff, total_out);
|
||||||
|
set_te16(&eho->e_shstrndx, 1);
|
||||||
|
fo->write(shdr_aa, sizeof(shdr_aa));
|
||||||
|
total_out += sizeof(shdr_aa);
|
||||||
|
|
||||||
|
fo->seek(0, SEEK_SET);
|
||||||
|
fo->write(eho, sizeof(*eho));
|
||||||
|
fo->seek(0, SEEK_END);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft)
|
||||||
|
{
|
||||||
|
if (!xct_off) {
|
||||||
|
overlay_offset = sz_elf_hdrs + sizeof(linfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_Shdrs(fo);
|
||||||
|
if (opt->o_unix.preserve_build_id) {
|
||||||
|
// 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(&elfout.ehdr.e_shoff,len);
|
||||||
|
|
||||||
|
int const ssize = sizeof(shdrout);
|
||||||
|
|
||||||
|
shdrout.shdr[2].sh_offset = len+ssize;
|
||||||
|
shdrout.shdr[1].sh_offset = shdrout.shdr[2].sh_offset+shdrout.shdr[2].sh_size;
|
||||||
|
|
||||||
|
fo->write(&shdrout, ssize);
|
||||||
|
|
||||||
|
fo->write(o_shstrtab,shdrout.shdr[2].sh_size);
|
||||||
|
fo->write(buildid_data,shdrout.shdr[1].sh_size);
|
||||||
|
}
|
||||||
|
|
||||||
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
// Cannot pre-round .p_memsz. If .p_filesz < .p_memsz, then kernel
|
||||||
// tries to make .bss, which requires PF_W.
|
// tries to make .bss, which requires PF_W.
|
||||||
@@ -5939,18 +6096,29 @@ void PackLinuxElf64::un_shlib_1(
|
|||||||
fi->seek(0, SEEK_SET);
|
fi->seek(0, SEEK_SET);
|
||||||
fi->readx(ibuf, umin(blocksize, file_size));
|
fi->readx(ibuf, umin(blocksize, file_size));
|
||||||
|
|
||||||
|
// Determine if the extra page with copy of _Shdrs was spliced in.
|
||||||
|
// This used to be the result of --anroid-shlib.
|
||||||
|
// But in 2023-02 the fowarding of ARM_ATTRIBUTES (by appending)
|
||||||
|
// takes care of this, so the 5th word before e_entry does not
|
||||||
|
// have the low bit 1, so is_asl should not be set.
|
||||||
|
// However, .so that were compressed before 2023-03
|
||||||
|
// may be marked.
|
||||||
e_shoff = get_te64(&ehdri.e_shoff);
|
e_shoff = get_te64(&ehdri.e_shoff);
|
||||||
|
if (e_shoff && e_shnum
|
||||||
// +36: (sizeof(PackHeader) + sizeof(overlay_offset))
|
// +36: (sizeof(PackHeader) + sizeof(overlay_offset))
|
||||||
// after Shdrs for ARM_ATTRIBUTES
|
// after Shdrs for ARM_ATTRIBUTES
|
||||||
if (e_shoff && e_shnum
|
&& (((e_shoff + sizeof(Elf64_Shdr) * e_shnum) + 36) < (upx_uint64_t)file_size)
|
||||||
&& ((e_shoff + sizeof(Elf64_Shdr) * e_shnum) + 36) < (upx_uint64_t)file_size) { // --android-shlib
|
) { // possible --android-shlib
|
||||||
is_asl = 1;
|
unsigned x = get_te32(&file_image[get_te64(&ehdri.e_entry) - (1+ 4)*sizeof(int)]);
|
||||||
fi->seek(e_shoff, SEEK_SET);
|
if (1 & x) { // the clincher
|
||||||
mb_shdr.alloc( sizeof(Elf64_Shdr) * e_shnum);
|
is_asl = 1;
|
||||||
shdri = (Elf64_Shdr *)mb_shdr.getVoidPtr();
|
fi->seek(e_shoff, SEEK_SET);
|
||||||
fi->readx(shdri, sizeof(Elf64_Shdr) * e_shnum);
|
mb_shdr.alloc( sizeof(Elf64_Shdr) * e_shnum);
|
||||||
yct_off = get_te64(&shdri->sh_offset); // for the output file (de-compresssed)
|
shdri = (Elf64_Shdr *)mb_shdr.getVoidPtr();
|
||||||
xct_off = asl_delta + yct_off; // for the input file (compressed)
|
fi->readx(shdri, sizeof(Elf64_Shdr) * e_shnum);
|
||||||
|
yct_off = get_te64(&shdri->sh_offset); // for the output file (de-compresssed)
|
||||||
|
xct_off = asl_delta + yct_off; // for the input file (compressed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decompress first Extent. Old style covers [0, xct_off)
|
// Decompress first Extent. Old style covers [0, xct_off)
|
||||||
@@ -6397,6 +6565,11 @@ void PackLinuxElf32::un_DT_INIT(
|
|||||||
else if (R_ARM_ABS32 == r_type) {
|
else if (R_ARM_ABS32 == r_type) {
|
||||||
word = 0;
|
word = 0;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
char msg[40]; snprintf(msg, sizeof(msg), "unknown relocation: %#x",
|
||||||
|
r_type);
|
||||||
|
throwCantUnpack(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (Elf32_Ehdr::EM_386 == e_machine) {
|
else if (Elf32_Ehdr::EM_386 == e_machine) {
|
||||||
if (R_386_RELATIVE == r_type) {
|
if (R_386_RELATIVE == r_type) {
|
||||||
@@ -6409,6 +6582,11 @@ void PackLinuxElf32::un_DT_INIT(
|
|||||||
else if (R_386_32 == r_type) {
|
else if (R_386_32 == r_type) {
|
||||||
word = 0;
|
word = 0;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
char msg[40]; snprintf(msg, sizeof(msg), "unknown relocation: %#x",
|
||||||
|
r_type);
|
||||||
|
throwCantUnpack(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (fo) {
|
if (fo) {
|
||||||
fo->seek(arr_off, SEEK_SET);
|
fo->seek(arr_off, SEEK_SET);
|
||||||
@@ -6505,7 +6683,10 @@ void PackLinuxElf64::un_DT_INIT(
|
|||||||
case Elf64_Dyn::DT_RELA: { dt_rela = val; } break;
|
case Elf64_Dyn::DT_RELA: { dt_rela = val; } break;
|
||||||
case Elf64_Dyn::DT_JMPREL: { dt_jmprel = val; } break;
|
case Elf64_Dyn::DT_JMPREL: { dt_jmprel = val; } break;
|
||||||
case Elf64_Dyn::DT_PLTRELSZ: { dt_pltrelsz = val;
|
case Elf64_Dyn::DT_PLTRELSZ: { dt_pltrelsz = val;
|
||||||
n_plt = 3+ (dt_pltrelsz / sizeof(Elf64_Rela)); // FIXME: "3+"
|
n_plt = dt_pltrelsz / sizeof(Elf32_Rel);
|
||||||
|
if (is_asl) {
|
||||||
|
n_plt += 3; // FIXME
|
||||||
|
}
|
||||||
}; break;
|
}; break;
|
||||||
|
|
||||||
case Elf64_Dyn::DT_PLTGOT: { plt_va = dt_pltgot = val; (void)dt_pltgot;}
|
case Elf64_Dyn::DT_PLTGOT: { plt_va = dt_pltgot = val; (void)dt_pltgot;}
|
||||||
@@ -6513,11 +6694,11 @@ void PackLinuxElf64::un_DT_INIT(
|
|||||||
case Elf64_Dyn::DT_PREINIT_ARRAY:
|
case Elf64_Dyn::DT_PREINIT_ARRAY:
|
||||||
case Elf64_Dyn::DT_INIT_ARRAY:
|
case Elf64_Dyn::DT_INIT_ARRAY:
|
||||||
case Elf64_Dyn::DT_FINI_ARRAY:
|
case Elf64_Dyn::DT_FINI_ARRAY:
|
||||||
case Elf64_Dyn::DT_FINI: {
|
case Elf64_Dyn::DT_FINI: if (is_asl) {
|
||||||
set_te64(&dyn->d_val, val - asl_delta);
|
set_te64(&dyn->d_val, val - asl_delta);
|
||||||
}; break;
|
}; break;
|
||||||
} // end switch() on tag when is_asl
|
} // end switch() on tag when is_asl
|
||||||
if (upx_dt_init == tag) {
|
if (upx_dt_init == tag) { // the easy case
|
||||||
if (Elf64_Dyn::DT_INIT == tag) {
|
if (Elf64_Dyn::DT_INIT == tag) {
|
||||||
set_te64(&dyn->d_val, old_dtinit);
|
set_te64(&dyn->d_val, old_dtinit);
|
||||||
if (!old_dtinit) { // compressor took the slot
|
if (!old_dtinit) { // compressor took the slot
|
||||||
@@ -6525,28 +6706,67 @@ void PackLinuxElf64::un_DT_INIT(
|
|||||||
dyn->d_val = 0;
|
dyn->d_val = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Elf64_Dyn::DT_INIT_ARRAY == tag
|
// Apparently the hard case is common for some Android IDEs.
|
||||||
|
else if (Elf32_Dyn::DT_INIT_ARRAY == tag
|
||||||
|| Elf64_Dyn::DT_PREINIT_ARRAY == tag) {
|
|| Elf64_Dyn::DT_PREINIT_ARRAY == tag) {
|
||||||
// The slot must have a R_*_RELATIVE relocation (is_shlib,
|
// 'val' is the RVA of the first slot, which is the slot that
|
||||||
// after all), but ElfXX_Rela ignores the initial contents!
|
// the compressor changed to be the entry to the run-time stub.
|
||||||
// So changing the value will get ignored. Do it anyway.
|
Elf64_Rel *rp = (Elf64_Rel *)elf_find_dynamic(Elf64_Dyn::DT_NULL);
|
||||||
// FIXME: we must fix the Rela ?
|
((Elf64_Dyn *)elf_find_dynptr(Elf64_Dyn::DT_NULL))->d_val = 0;
|
||||||
Elf64_Phdr const *phdr = phdro;
|
if (rp) {
|
||||||
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
|
// Compressor saved the original *rp in dynsym[0]
|
||||||
upx_uint64_t vaddr = get_te64(&phdr->p_vaddr);
|
Elf64_Rel *rp_unc = (Elf64_Rel *)&dynsym[0]; // pointer
|
||||||
upx_uint64_t filesz = get_te64(&phdr->p_filesz);
|
rp->r_info = rp_unc->r_info; // restore original r_info; r_offset not touched
|
||||||
unsigned q = val - (is_asl ? asl_delta : 0) - vaddr;
|
|
||||||
if (q < filesz) {
|
unsigned e_entry = get_te64(&ehdri.e_entry);
|
||||||
upx_uint64_t offset = get_te64(&phdr->p_offset);
|
unsigned init_rva = get_te64(&file_image[e_entry - 3*sizeof(unsigned)]);
|
||||||
// Rela overwrites the target; assumed default is 0
|
unsigned arr_rva = get_te64(&rp_unc->r_offset);
|
||||||
upx_uint64_t oldval = 0; //set_te64(&oldval, old_dtinit);
|
Elf64_Phdr const *phdr = elf_find_Phdr_for_va(arr_rva, phdro, e_phnum);
|
||||||
// Counter-act unRel64 if asl_delta
|
unsigned arr_off = (arr_rva - get_te64(&phdr->p_vaddr)) + get_te64(&phdr->p_offset);
|
||||||
// FIXME? the in-memory copy?
|
|
||||||
if (fo) {
|
rp_unc->r_offset = 0; rp_unc->r_info = 0;
|
||||||
fo->seek(q + offset, SEEK_SET);
|
if (fo) {
|
||||||
fo->write(&oldval, sizeof(oldval));
|
fo->seek(elf_unsigned_dynamic(Elf64_Dyn::DT_SYMTAB), SEEK_SET);
|
||||||
|
fo->rewrite(rp_unc, sizeof(Elf64_Rel)); // clear dynsym[0]
|
||||||
|
|
||||||
|
fo->seek((char *)rp - (char *)&file_image[0], SEEK_SET);
|
||||||
|
fo->rewrite(rp, sizeof(*rp)); // restore original *rp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set arr[0] to the first user init routine.
|
||||||
|
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) {
|
||||||
|
set_te64(&word, init_rva);
|
||||||
}
|
}
|
||||||
break;
|
else if (R_AARCH64_ABS64 == r_type) {
|
||||||
|
word = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char msg[40]; snprintf(msg, sizeof(msg), "unknown relocation: %#x",
|
||||||
|
r_type);
|
||||||
|
throwCantUnpack(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Elf64_Ehdr::EM_AMD64 == e_machine) {
|
||||||
|
if (R_X86_64_RELATIVE == r_type) {
|
||||||
|
set_te64(&word, init_rva);
|
||||||
|
}
|
||||||
|
else if (R_X86_64_64 == r_type) {
|
||||||
|
word = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char msg[40]; snprintf(msg, sizeof(msg), "unknown relocation: %#x",
|
||||||
|
r_type);
|
||||||
|
throwCantUnpack(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fo) {
|
||||||
|
fo->seek(arr_off, SEEK_SET);
|
||||||
|
fo->rewrite(&word, sizeof(word));
|
||||||
|
fo->seek(0, SEEK_END);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7147,6 +7367,23 @@ Elf32_Dyn *PackLinuxElf32::elf_find_dynptr(unsigned int key) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Elf64_Dyn *PackLinuxElf64::elf_find_dynptr(unsigned int key) const
|
||||||
|
{
|
||||||
|
Elf64_Dyn *dynp= dynseg;
|
||||||
|
if (dynp) {
|
||||||
|
Elf64_Dyn *const last = (Elf64_Dyn *)(sz_dynseg + (char *)dynseg);
|
||||||
|
for (; dynp < last; ++dynp) {
|
||||||
|
if (get_te64(&dynp->d_tag)==key) {
|
||||||
|
return dynp;
|
||||||
|
}
|
||||||
|
if (Elf64_Dyn::DT_NULL == dynp->d_tag) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
PackLinuxElf32::elf_find_dynamic(unsigned int key) const
|
PackLinuxElf32::elf_find_dynamic(unsigned int key) const
|
||||||
{
|
{
|
||||||
|
|||||||
+6
-2
@@ -155,6 +155,7 @@ protected:
|
|||||||
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
||||||
virtual off_t pack3(OutputFile *, Filter &) override; // append loader
|
virtual off_t pack3(OutputFile *, Filter &) override; // append loader
|
||||||
virtual void pack4(OutputFile *, Filter &) override; // append pack header
|
virtual void pack4(OutputFile *, Filter &) override; // append pack header
|
||||||
|
virtual void forward_Shdrs(OutputFile *fo);
|
||||||
virtual void unpack(OutputFile *fo) override;
|
virtual void unpack(OutputFile *fo) override;
|
||||||
virtual void un_asl_dynsym(unsigned orig_file_size, OutputFile *);
|
virtual void un_asl_dynsym(unsigned orig_file_size, OutputFile *);
|
||||||
virtual void un_shlib_1(
|
virtual void un_shlib_1(
|
||||||
@@ -312,6 +313,7 @@ protected:
|
|||||||
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
||||||
virtual off_t pack3(OutputFile *, Filter &) override; // append loader
|
virtual off_t pack3(OutputFile *, Filter &) override; // append loader
|
||||||
virtual void pack4(OutputFile *, Filter &) override; // append pack header
|
virtual void pack4(OutputFile *, Filter &) override; // append pack header
|
||||||
|
virtual void forward_Shdrs(OutputFile *fo);
|
||||||
virtual void unpack(OutputFile *fo) override;
|
virtual void unpack(OutputFile *fo) override;
|
||||||
virtual void un_asl_dynsym(unsigned orig_file_size, OutputFile *);
|
virtual void un_asl_dynsym(unsigned orig_file_size, OutputFile *);
|
||||||
virtual void un_shlib_1(
|
virtual void un_shlib_1(
|
||||||
@@ -352,10 +354,11 @@ protected:
|
|||||||
|
|
||||||
virtual Elf64_Sym const *elf_lookup(char const *) const;
|
virtual Elf64_Sym const *elf_lookup(char const *) const;
|
||||||
virtual upx_uint64_t elf_get_offset_from_address(upx_uint64_t) const;
|
virtual upx_uint64_t elf_get_offset_from_address(upx_uint64_t) const;
|
||||||
virtual Elf64_Phdr *elf_find_Phdr_for_va(upx_uint64_t addr, Elf64_Phdr *phdr, unsigned phnum);
|
virtual Elf64_Phdr const *elf_find_Phdr_for_va(upx_uint64_t addr, Elf64_Phdr const *phdr, unsigned phnum);
|
||||||
Elf64_Phdr const *elf_find_ptype(unsigned type, Elf64_Phdr const *phdr0, unsigned phnum);
|
Elf64_Phdr const *elf_find_ptype(unsigned type, Elf64_Phdr const *phdr0, unsigned phnum);
|
||||||
Elf64_Shdr const *elf_find_section_name(char const *) const;
|
Elf64_Shdr const *elf_find_section_name(char const *) const;
|
||||||
Elf64_Shdr *elf_find_section_type(unsigned) const;
|
Elf64_Shdr *elf_find_section_type(unsigned) const;
|
||||||
|
Elf64_Dyn *elf_find_dynptr(unsigned) const;
|
||||||
unsigned elf_find_table_size(unsigned dt_type, unsigned sh_type);
|
unsigned elf_find_table_size(unsigned dt_type, unsigned sh_type);
|
||||||
void sort_DT64_offsets(Elf64_Dyn const *const dynp0);
|
void sort_DT64_offsets(Elf64_Dyn const *const dynp0);
|
||||||
int is_LOAD64(Elf64_Phdr const *phdr) const; // beware confusion with (1+ LO_PROC)
|
int is_LOAD64(Elf64_Phdr const *phdr) const; // beware confusion with (1+ LO_PROC)
|
||||||
@@ -389,8 +392,9 @@ protected:
|
|||||||
Elf64_Sym const *jni_onload_sym;
|
Elf64_Sym const *jni_onload_sym;
|
||||||
|
|
||||||
Elf64_Shdr *sec_strndx;
|
Elf64_Shdr *sec_strndx;
|
||||||
Elf64_Shdr const *sec_dynsym;
|
Elf64_Shdr *sec_dynsym;
|
||||||
Elf64_Shdr const *sec_dynstr;
|
Elf64_Shdr const *sec_dynstr;
|
||||||
|
Elf64_Shdr *sec_arm_attr; // SHT_ARM_ATTRIBUTES;
|
||||||
|
|
||||||
__packed_struct(cprElfHdr1)
|
__packed_struct(cprElfHdr1)
|
||||||
Elf64_Ehdr ehdr;
|
Elf64_Ehdr ehdr;
|
||||||
|
|||||||
Reference in New Issue
Block a user