PackLinuxElf64::canPack_Shdr
modified: p_lx_elf.cpp modified: p_lx_elf.h
This commit is contained in:
parent
14d75b222f
commit
0cc0e51d5d
282
src/p_lx_elf.cpp
282
src/p_lx_elf.cpp
@ -1537,9 +1537,11 @@ PackLinuxElf32::buildLinuxLoader(
|
|||||||
}
|
}
|
||||||
else { // main program with ELF1 de-compressor
|
else { // main program with ELF1 de-compressor
|
||||||
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
|
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
|
||||||
unsigned fold_hdrlen = upx::umax(0x80u, usizeof(hf->ehdr) +
|
unsigned fold_hdrlen = usizeof(hf->ehdr) +
|
||||||
get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum) +
|
get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum);
|
||||||
usizeof(l_info) );
|
if (this->e_machine==Elf32_Ehdr::EM_MIPS) {
|
||||||
|
fold_hdrlen = upx::umax(fold_hdrlen, (unsigned)0x80);
|
||||||
|
}
|
||||||
uncLoader = fold_hdrlen + fold;
|
uncLoader = fold_hdrlen + fold;
|
||||||
sz_unc = ((szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen));
|
sz_unc = ((szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen));
|
||||||
method = ph.method;
|
method = ph.method;
|
||||||
@ -1699,9 +1701,8 @@ PackLinuxElf64::buildLinuxLoader(
|
|||||||
}
|
}
|
||||||
else { // not shlib: main program with ELF1 de-compressor
|
else { // not shlib: main program with ELF1 de-compressor
|
||||||
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
|
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
|
||||||
unsigned fold_hdrlen = upx::umax(0x80u, usizeof(hf->ehdr) +
|
unsigned fold_hdrlen = usizeof(hf->ehdr) +
|
||||||
get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum) +
|
get_te16(&hf->ehdr.e_phentsize) * get_te16(&hf->ehdr.e_phnum));
|
||||||
usizeof(l_info) );
|
|
||||||
uncLoader = fold_hdrlen + fold;
|
uncLoader = fold_hdrlen + fold;
|
||||||
sz_unc = ((szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen));
|
sz_unc = ((szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen));
|
||||||
method = ph.method;
|
method = ph.method;
|
||||||
@ -2820,6 +2821,150 @@ bad:
|
|||||||
return xct_va;
|
return xct_va;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upx_uint64_t PackLinuxElf64::canPack_Shdr(Elf64_Phdr const *pload_x0)
|
||||||
|
{
|
||||||
|
Elf64_Shdr const *shdr_xva = nullptr;
|
||||||
|
Elf64_Shdr const *shdr = shdri;
|
||||||
|
for (int j= e_shnum; --j>=0; ++shdr) {
|
||||||
|
unsigned const sh_type = get_te32(&shdr->sh_type);
|
||||||
|
if (Elf64_Shdr::SHF_EXECINSTR & get_te64(&shdr->sh_flags)) {
|
||||||
|
xct_va = umin(xct_va, get_te64(&shdr->sh_addr));
|
||||||
|
}
|
||||||
|
// Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY.
|
||||||
|
if (!user_init_rp && (
|
||||||
|
( Elf64_Dyn::DT_PREINIT_ARRAY==upx_dt_init
|
||||||
|
&& Elf64_Shdr::SHT_PREINIT_ARRAY==sh_type)
|
||||||
|
|| ( Elf64_Dyn::DT_INIT_ARRAY ==upx_dt_init
|
||||||
|
&& Elf64_Shdr::SHT_INIT_ARRAY ==sh_type) )) {
|
||||||
|
unsigned user_init_ava = get_te64(&shdr->sh_addr);
|
||||||
|
user_init_off = get_te64(&shdr->sh_offset);
|
||||||
|
if ((u64_t)file_size <= user_init_off) {
|
||||||
|
char msg[70]; snprintf(msg, sizeof(msg),
|
||||||
|
"bad Elf64_Shdr[%d].sh_offset %#x",
|
||||||
|
-1+ e_shnum - j, user_init_off);
|
||||||
|
throwCantPack(msg);
|
||||||
|
}
|
||||||
|
// Check that &file_image[user_init_off] has
|
||||||
|
// *_RELATIVE or *_ABS* relocation, and fetch user_init_va.
|
||||||
|
// If Elf_Rela then the actual value is in Rela.r_addend.
|
||||||
|
int z_rel = dt_table[Elf64_Dyn::DT_RELA];
|
||||||
|
int z_rsz = dt_table[Elf64_Dyn::DT_RELASZ];
|
||||||
|
if (z_rel && z_rsz) {
|
||||||
|
upx_uint64_t rel_off = get_te64(&dynseg[-1+ z_rel].d_val);
|
||||||
|
if ((u64_t)file_size <= rel_off) {
|
||||||
|
char msg[70]; snprintf(msg, sizeof(msg),
|
||||||
|
"bad Elf64_Dynamic[DT_RELA] %#llx\n",
|
||||||
|
rel_off);
|
||||||
|
throwCantPack(msg);
|
||||||
|
}
|
||||||
|
Elf64_Rela *rp = (Elf64_Rela *)&file_image[rel_off];
|
||||||
|
upx_uint64_t relsz = get_te64(&dynseg[-1+ z_rsz].d_val);
|
||||||
|
if ((u64_t)file_size <= relsz) {
|
||||||
|
char msg[70]; snprintf(msg, sizeof(msg),
|
||||||
|
"bad Elf64_Dynamic[DT_RELASZ] %#llx\n",
|
||||||
|
relsz);
|
||||||
|
throwCantPack(msg);
|
||||||
|
}
|
||||||
|
Elf64_Rela *last = (Elf64_Rela *)(relsz + (char *)rp);
|
||||||
|
for (; rp < last; ++rp) {
|
||||||
|
upx_uint64_t r_va = get_te64(&rp->r_offset);
|
||||||
|
if (r_va == user_init_ava) { // found the Elf64_Rela
|
||||||
|
user_init_rp = rp;
|
||||||
|
upx_uint64_t r_info = get_te64(&rp->r_info);
|
||||||
|
unsigned r_type = ELF64_R_TYPE(r_info);
|
||||||
|
set_te32(&dynsym[0].st_name, r_va); // for decompressor
|
||||||
|
set_te64(&dynsym[0].st_value, r_info);
|
||||||
|
set_te64(&dynsym[0].st_size, get_te64(&rp->r_addend));
|
||||||
|
if (Elf64_Ehdr::EM_AARCH64 == e_machine) {
|
||||||
|
if (R_AARCH64_RELATIVE == r_type) {
|
||||||
|
user_init_va = get_te64(&rp->r_addend);
|
||||||
|
}
|
||||||
|
else if (R_AARCH64_ABS64 == r_type) {
|
||||||
|
user_init_va = get_te64(&dynsym[ELF64_R_SYM(r_info)].st_value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char msg[50]; snprintf(msg, sizeof(msg),
|
||||||
|
"bad relocation %#llx DT_INIT_ARRAY[0]",
|
||||||
|
r_info);
|
||||||
|
throwCantPack(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Elf64_Ehdr::EM_X86_64 == e_machine) {
|
||||||
|
if (R_X86_64_RELATIVE == r_type) {
|
||||||
|
user_init_va = get_te64(&rp->r_addend);
|
||||||
|
}
|
||||||
|
else if (R_X86_64_64 == r_type) {
|
||||||
|
user_init_va = get_te64(&dynsym[ELF64_R_SYM(r_info)].st_value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char msg[50]; snprintf(msg, sizeof(msg),
|
||||||
|
"bad relocation %#llx DT_INIT_ARRAY[0]",
|
||||||
|
r_info);
|
||||||
|
throwCantPack(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned const p_filesz = get_te64(&pload_x0->p_filesz);
|
||||||
|
if (!((user_init_va - xct_va) < p_filesz)) {
|
||||||
|
// Not in executable portion of first executable PT_LOAD.
|
||||||
|
if (0==user_init_va && opt->o_unix.android_shlib) {
|
||||||
|
// Android allows (0 ==> skip) ?
|
||||||
|
upx_dt_init = 0; // force steal of 'extra' DT_NULL
|
||||||
|
// XXX: FIXME: depends on SHT_DYNAMIC coming later
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char msg[70]; snprintf(msg, sizeof(msg),
|
||||||
|
"bad init address %#x in Elf64_Shdr[%d].%#x\n",
|
||||||
|
(unsigned)user_init_va, -1+ e_shnum - j, user_init_off);
|
||||||
|
throwCantPack(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// By default /usr/bin/ld leaves 4 extra DT_NULL to support pre-linking.
|
||||||
|
// Take one as a last resort.
|
||||||
|
if ((Elf64_Dyn::DT_INIT==upx_dt_init || !upx_dt_init)
|
||||||
|
&& Elf64_Shdr::SHT_DYNAMIC == sh_type) {
|
||||||
|
upx_uint64_t sh_offset = get_te64(&shdr->sh_offset);
|
||||||
|
upx_uint64_t sh_size = get_te64(&shdr->sh_size);
|
||||||
|
if ((upx_uint64_t)file_size < sh_size
|
||||||
|
|| (upx_uint64_t)file_size < sh_offset
|
||||||
|
|| ((upx_uint64_t)file_size - sh_offset) < sh_size) {
|
||||||
|
throwCantPack("bad SHT_DYNAMIC");
|
||||||
|
}
|
||||||
|
unsigned const n = sh_size / sizeof(Elf64_Dyn);
|
||||||
|
Elf64_Dyn *dynp = (Elf64_Dyn *)&file_image[sh_offset];
|
||||||
|
for (; Elf64_Dyn::DT_NULL != dynp->d_tag; ++dynp) {
|
||||||
|
if (upx_dt_init == get_te64(&dynp->d_tag)) {
|
||||||
|
break; // re-found DT_INIT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((1+ dynp) < (n+ dynseg)) { // not the terminator, so take it
|
||||||
|
user_init_va = get_te64(&dynp->d_val); // 0 if (0==upx_dt_init)
|
||||||
|
set_te64(&dynp->d_tag, upx_dt_init = Elf64_Dyn::DT_INIT);
|
||||||
|
user_init_off = (char const *)&dynp->d_val - (char const *)&file_image[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If shdr_xva->sh_size is too small, then probably it won't compress.
|
||||||
|
// So look for a Shdr that has PROGBITS and not SHF_WRITE, which is
|
||||||
|
// much larger, and use that for the compressibility decision.
|
||||||
|
if (shdr_xva->sh_size < 0x1000) {
|
||||||
|
shdr = shdr_xva;
|
||||||
|
while (SHT_PROGBITS == get_te32(&shdr[-1].sh_type)) --shdr; // backup
|
||||||
|
for (; SHT_PROGBITS == get_te32(&shdr->sh_type)
|
||||||
|
&& !(SHF_WRITE & get_te64(&shdr->sh_flags)); ++shdr) {
|
||||||
|
if (0x4000 <= get_te64(&shdr->sh_size)) {
|
||||||
|
xct_va = get_te64(&shdr->sh_addr); // hopefully more compressible
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return xct_va;
|
||||||
|
}
|
||||||
|
|
||||||
tribool PackLinuxElf32::canPack()
|
tribool PackLinuxElf32::canPack()
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
@ -3345,132 +3490,9 @@ tribool PackLinuxElf64::canPack()
|
|||||||
if (Elf64_Ehdr::EM_PPC64 == get_te16(&ehdr->e_machine)) {
|
if (Elf64_Ehdr::EM_PPC64 == get_te16(&ehdr->e_machine)) {
|
||||||
throwCantPack("This test UPX cannot pack .so for PowerPC64; coming soon.");
|
throwCantPack("This test UPX cannot pack .so for PowerPC64; coming soon.");
|
||||||
}
|
}
|
||||||
Elf64_Shdr const *shdr = shdri;
|
|
||||||
xct_va = ~0ull;
|
xct_va = ~0ull;
|
||||||
if (e_shnum) {
|
if (e_shnum) {
|
||||||
for (int j= e_shnum; --j>=0; ++shdr) {
|
xct_va = canPack_Shdr(pload_x0);
|
||||||
unsigned const sh_type = get_te32(&shdr->sh_type);
|
|
||||||
if (Elf64_Shdr::SHF_EXECINSTR & get_te64(&shdr->sh_flags)) {
|
|
||||||
xct_va = umin(xct_va, get_te64(&shdr->sh_addr));
|
|
||||||
}
|
|
||||||
// Hook the first slot of DT_PREINIT_ARRAY or DT_INIT_ARRAY.
|
|
||||||
if (!user_init_rp && (
|
|
||||||
( Elf64_Dyn::DT_PREINIT_ARRAY==upx_dt_init
|
|
||||||
&& Elf64_Shdr::SHT_PREINIT_ARRAY==sh_type)
|
|
||||||
|| ( Elf64_Dyn::DT_INIT_ARRAY ==upx_dt_init
|
|
||||||
&& Elf64_Shdr::SHT_INIT_ARRAY ==sh_type) )) {
|
|
||||||
unsigned user_init_ava = get_te64(&shdr->sh_addr);
|
|
||||||
user_init_off = get_te64(&shdr->sh_offset);
|
|
||||||
if ((u64_t)file_size <= user_init_off) {
|
|
||||||
char msg[70]; snprintf(msg, sizeof(msg),
|
|
||||||
"bad Elf64_Shdr[%d].sh_offset %#x",
|
|
||||||
-1+ e_shnum - j, user_init_off);
|
|
||||||
throwCantPack(msg);
|
|
||||||
}
|
|
||||||
// Check that &file_image[user_init_off] has
|
|
||||||
// *_RELATIVE or *_ABS* relocation, and fetch user_init_va.
|
|
||||||
// If Elf_Rela then the actual value is in Rela.r_addend.
|
|
||||||
int z_rel = dt_table[Elf64_Dyn::DT_RELA];
|
|
||||||
int z_rsz = dt_table[Elf64_Dyn::DT_RELASZ];
|
|
||||||
if (z_rel && z_rsz) {
|
|
||||||
upx_uint64_t rel_off = get_te64(&dynseg[-1+ z_rel].d_val);
|
|
||||||
if ((u64_t)file_size <= rel_off) {
|
|
||||||
char msg[70]; snprintf(msg, sizeof(msg),
|
|
||||||
"bad Elf64_Dynamic[DT_RELA] %#llx\n",
|
|
||||||
rel_off);
|
|
||||||
throwCantPack(msg);
|
|
||||||
}
|
|
||||||
Elf64_Rela *rp = (Elf64_Rela *)&file_image[rel_off];
|
|
||||||
upx_uint64_t relsz = get_te64(&dynseg[-1+ z_rsz].d_val);
|
|
||||||
if ((u64_t)file_size <= relsz) {
|
|
||||||
char msg[70]; snprintf(msg, sizeof(msg),
|
|
||||||
"bad Elf64_Dynamic[DT_RELASZ] %#llx\n",
|
|
||||||
relsz);
|
|
||||||
throwCantPack(msg);
|
|
||||||
}
|
|
||||||
Elf64_Rela *last = (Elf64_Rela *)(relsz + (char *)rp);
|
|
||||||
for (; rp < last; ++rp) {
|
|
||||||
upx_uint64_t r_va = get_te64(&rp->r_offset);
|
|
||||||
if (r_va == user_init_ava) { // found the Elf64_Rela
|
|
||||||
user_init_rp = rp;
|
|
||||||
upx_uint64_t r_info = get_te64(&rp->r_info);
|
|
||||||
unsigned r_type = ELF64_R_TYPE(r_info);
|
|
||||||
set_te32(&dynsym[0].st_name, r_va); // for decompressor
|
|
||||||
set_te64(&dynsym[0].st_value, r_info);
|
|
||||||
set_te64(&dynsym[0].st_size, get_te64(&rp->r_addend));
|
|
||||||
if (Elf64_Ehdr::EM_AARCH64 == e_machine) {
|
|
||||||
if (R_AARCH64_RELATIVE == r_type) {
|
|
||||||
user_init_va = get_te64(&rp->r_addend);
|
|
||||||
}
|
|
||||||
else if (R_AARCH64_ABS64 == r_type) {
|
|
||||||
user_init_va = get_te64(&dynsym[ELF64_R_SYM(r_info)].st_value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char msg[50]; snprintf(msg, sizeof(msg),
|
|
||||||
"bad relocation %#llx DT_INIT_ARRAY[0]",
|
|
||||||
r_info);
|
|
||||||
throwCantPack(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Elf64_Ehdr::EM_X86_64 == e_machine) {
|
|
||||||
if (R_X86_64_RELATIVE == r_type) {
|
|
||||||
user_init_va = get_te64(&rp->r_addend);
|
|
||||||
}
|
|
||||||
else if (R_X86_64_64 == r_type) {
|
|
||||||
user_init_va = get_te64(&dynsym[ELF64_R_SYM(r_info)].st_value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char msg[50]; snprintf(msg, sizeof(msg),
|
|
||||||
"bad relocation %#llx DT_INIT_ARRAY[0]",
|
|
||||||
r_info);
|
|
||||||
throwCantPack(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsigned const p_filesz = get_te64(&pload_x0->p_filesz);
|
|
||||||
if (!((user_init_va - xct_va) < p_filesz)) {
|
|
||||||
// Not in executable portion of first executable PT_LOAD.
|
|
||||||
if (0==user_init_va && opt->o_unix.android_shlib) {
|
|
||||||
// Android allows (0 ==> skip) ?
|
|
||||||
upx_dt_init = 0; // force steal of 'extra' DT_NULL
|
|
||||||
// XXX: FIXME: depends on SHT_DYNAMIC coming later
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
char msg[70]; snprintf(msg, sizeof(msg),
|
|
||||||
"bad init address %#x in Elf64_Shdr[%d].%#x\n",
|
|
||||||
(unsigned)user_init_va, -1+ e_shnum - j, user_init_off);
|
|
||||||
throwCantPack(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// By default /usr/bin/ld leaves 4 extra DT_NULL to support pre-linking.
|
|
||||||
// Take one as a last resort.
|
|
||||||
if ((Elf64_Dyn::DT_INIT==upx_dt_init || !upx_dt_init)
|
|
||||||
&& Elf64_Shdr::SHT_DYNAMIC == sh_type) {
|
|
||||||
upx_uint64_t sh_offset = get_te64(&shdr->sh_offset);
|
|
||||||
upx_uint64_t sh_size = get_te64(&shdr->sh_size);
|
|
||||||
if ((upx_uint64_t)file_size < sh_size
|
|
||||||
|| (upx_uint64_t)file_size < sh_offset
|
|
||||||
|| ((upx_uint64_t)file_size - sh_offset) < sh_size) {
|
|
||||||
throwCantPack("bad SHT_DYNAMIC");
|
|
||||||
}
|
|
||||||
unsigned const n = sh_size / sizeof(Elf64_Dyn);
|
|
||||||
Elf64_Dyn *dynp = (Elf64_Dyn *)&file_image[sh_offset];
|
|
||||||
for (; Elf64_Dyn::DT_NULL != dynp->d_tag; ++dynp) {
|
|
||||||
if (upx_dt_init == get_te64(&dynp->d_tag)) {
|
|
||||||
break; // re-found DT_INIT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((1+ dynp) < (n+ dynseg)) { // not the terminator, so take it
|
|
||||||
user_init_va = get_te64(&dynp->d_val); // 0 if (0==upx_dt_init)
|
|
||||||
set_te64(&dynp->d_tag, upx_dt_init = Elf64_Dyn::DT_INIT);
|
|
||||||
user_init_off = (char const *)&dynp->d_val - (char const *)&file_image[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else { // no Sections; use heuristics
|
else { // no Sections; use heuristics
|
||||||
upx_uint64_t const strsz = elf_unsigned_dynamic(Elf64_Dyn::DT_STRSZ);
|
upx_uint64_t const strsz = elf_unsigned_dynamic(Elf64_Dyn::DT_STRSZ);
|
||||||
|
|||||||
@ -319,6 +319,7 @@ protected:
|
|||||||
virtual tribool canPack() override;
|
virtual tribool canPack() override;
|
||||||
virtual tribool canUnpack() override; // bool, except -1: format known, but not packed
|
virtual tribool canUnpack() override; // bool, except -1: format known, but not packed
|
||||||
|
|
||||||
|
virtual upx_uint64_t canPack_Shdr(Elf64_Phdr const *pload_x0);
|
||||||
virtual void pack1(OutputFile *, Filter &) override; // generate executable header
|
virtual void pack1(OutputFile *, Filter &) override; // generate executable header
|
||||||
virtual void asl_pack2_Shdrs(OutputFile *, unsigned pre_xct_top); // AndroidSharedLibrary processes Shdrs
|
virtual void asl_pack2_Shdrs(OutputFile *, unsigned pre_xct_top); // AndroidSharedLibrary processes Shdrs
|
||||||
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user