WIP: un_shlib_1
modified: p_lx_elf.cpp modified: p_lx_elf.h
This commit is contained in:
committed by
Markus F.X.J. Oberhumer
parent
bd4aca5c12
commit
181c752488
+60
-49
@@ -785,6 +785,7 @@ PackLinuxElf64::PackLinuxElf64help1(InputFile *f)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sz_phdrs = e_phnum * e_phentsize;
|
sz_phdrs = e_phnum * e_phentsize;
|
||||||
|
sz_elf_hdrs = sz_phdrs + sizeof(Elf64_Ehdr);
|
||||||
|
|
||||||
if (f && Elf64_Ehdr::ET_DYN!=e_type) {
|
if (f && Elf64_Ehdr::ET_DYN!=e_type) {
|
||||||
unsigned const len = sz_phdrs + e_phoff;
|
unsigned const len = sz_phdrs + e_phoff;
|
||||||
@@ -4594,7 +4595,7 @@ PackLinuxElf64::unRela64(
|
|||||||
|
|
||||||
void PackLinuxElf64::un_shlib_1(
|
void PackLinuxElf64::un_shlib_1(
|
||||||
OutputFile *const fo,
|
OutputFile *const fo,
|
||||||
Elf64_Phdr *const phdro,
|
MemBuffer &o_elfhdrs,
|
||||||
unsigned &c_adler,
|
unsigned &c_adler,
|
||||||
unsigned &u_adler,
|
unsigned &u_adler,
|
||||||
Elf64_Phdr const *const dynhdr,
|
Elf64_Phdr const *const dynhdr,
|
||||||
@@ -4602,7 +4603,7 @@ void PackLinuxElf64::un_shlib_1(
|
|||||||
unsigned const szb_info
|
unsigned const szb_info
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// The first PT_LOAD. Part is not compressed (for benefit of rtld.)
|
// Below xct_off is not compressed (for benefit of rtld.)
|
||||||
fi->seek(0, SEEK_SET);
|
fi->seek(0, SEEK_SET);
|
||||||
unsigned const limit_dynhdr = get_te64(&dynhdr->p_offset) + get_te64(&dynhdr->p_filesz);
|
unsigned const limit_dynhdr = get_te64(&dynhdr->p_offset) + get_te64(&dynhdr->p_filesz);
|
||||||
fi->readx(ibuf, limit_dynhdr);
|
fi->readx(ibuf, limit_dynhdr);
|
||||||
@@ -4646,62 +4647,73 @@ void PackLinuxElf64::un_shlib_1(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fo) {
|
|
||||||
fo->write(ibuf, xct_off);
|
|
||||||
}
|
|
||||||
total_in = xct_off;
|
|
||||||
total_out = xct_off;
|
|
||||||
|
|
||||||
// Decompress and unfilter the tail of PT_LOAD containing xct_off
|
// Decompress first Extent. Old style covers [0, xct_off);
|
||||||
fi->seek(xct_off + sizeof(linfo) + sizeof(p_info), SEEK_SET);
|
// new style covers just Elf headers: the rest below xct_off is constant!
|
||||||
struct b_info hdr;
|
fi->seek(xct_off, SEEK_SET);
|
||||||
fi->readx(&hdr, sizeof(hdr)); // Peek at b_info
|
struct {
|
||||||
fi->seek(-(off_t)sizeof(hdr), SEEK_CUR);
|
struct l_info l;
|
||||||
ph.c_len = get_te32(&hdr.sz_cpr);
|
struct p_info p;
|
||||||
ph.u_len = get_te32(&hdr.sz_unc);
|
struct b_info b;
|
||||||
|
} hdr;
|
||||||
|
fi->readx(&hdr, sizeof(hdr));
|
||||||
|
fi->seek(-(off_t)sizeof(struct b_info), SEEK_CUR);
|
||||||
|
if (hdr.l.l_magic != UPX_MAGIC_LE32
|
||||||
|
|| hdr.l.l_lsize != (unsigned)lsize
|
||||||
|
|| hdr.p.p_filesize != ph.u_file_size) {
|
||||||
|
throwCantUnpack("corrupt l_info/p_info");
|
||||||
|
}
|
||||||
|
ph.c_len = get_te32(&hdr.b.sz_cpr);
|
||||||
|
ph.u_len = get_te32(&hdr.b.sz_unc);
|
||||||
|
|
||||||
unpackExtent(ph.u_len, fo,
|
unpackExtent(ph.u_len, fo,
|
||||||
c_adler, u_adler, false, szb_info);
|
c_adler, u_adler, false, szb_info);
|
||||||
|
// Recover original Elf headers from current output file
|
||||||
|
InputFile u_fi;
|
||||||
|
u_fi.open(fo->getName(), 0);
|
||||||
|
u_fi.readx((void *)o_elfhdrs,o_elfhdrs.getSize());
|
||||||
|
u_fi.close();
|
||||||
|
|
||||||
|
// New style: up to xct_off
|
||||||
|
if (ph.u_len < xct_off) {
|
||||||
|
if (fo) {
|
||||||
|
fo->write(&ibuf[ph.u_len], xct_off - ph.u_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Tail of PT_LOAD beginning at xct_off
|
||||||
|
fi->readx(&hdr.b, sizeof(hdr.b));
|
||||||
|
fi->seek(-(off_t)sizeof(struct b_info), SEEK_CUR);
|
||||||
|
ph.c_len = get_te32(&hdr.b.sz_cpr);
|
||||||
|
ph.u_len = get_te32(&hdr.b.sz_unc);
|
||||||
|
unpackExtent(ph.u_len, fo, c_adler, u_adler, false, szb_info);
|
||||||
|
|
||||||
|
funpad4(fi);
|
||||||
|
unsigned const l_offset = fi->tell();
|
||||||
|
|
||||||
// Copy (slide) the remaining PT_LOAD; they are not compressed
|
// Copy (slide) the remaining PT_LOAD; they are not compressed
|
||||||
Elf64_Phdr *phdr = phdro;
|
// because relocation processing by rtld might alter their memory image
|
||||||
unsigned slide = 0;
|
Elf64_Phdr const *i_phdr = phdri;
|
||||||
int first = 0;
|
Elf64_Phdr const *o_phdr = (Elf64_Phdr const *)(1+ (Elf64_Ehdr const *)(void const *)o_elfhdrs);
|
||||||
for (unsigned k = 0; k < e_phnum; ++k, ++phdr) {
|
for (unsigned k = 0; k < e_phnum; ++k, ++i_phdr, ++o_phdr) {
|
||||||
unsigned type = get_te32(&phdr->p_type);
|
unsigned type = get_te32(&i_phdr->p_type);
|
||||||
unsigned vaddr = get_te64(&phdr->p_vaddr);
|
unsigned vaddr = get_te64(&i_phdr->p_vaddr);
|
||||||
unsigned offset = get_te64(&phdr->p_offset);
|
unsigned offset = get_te64(&i_phdr->p_offset);
|
||||||
unsigned filesz = get_te64(&phdr->p_filesz);
|
unsigned filesz = get_te64(&i_phdr->p_filesz);
|
||||||
if (xct_off <= vaddr) {
|
if (xct_off <= vaddr) {
|
||||||
if (PT_LOAD64==type) {
|
if (PT_LOAD64==type) {
|
||||||
if (0==first++) { // the partially-compressed PT_LOAD
|
|
||||||
set_te64(&phdr->p_filesz, ph.u_len + xct_off - vaddr);
|
|
||||||
set_te64(&phdr->p_memsz, ph.u_len + xct_off - vaddr);
|
|
||||||
}
|
|
||||||
else { // subsequent PT_LOAD
|
|
||||||
fi->seek(offset, SEEK_SET);
|
fi->seek(offset, SEEK_SET);
|
||||||
fi->readx(ibuf, filesz);
|
fi->readx(ibuf, filesz);
|
||||||
total_in += filesz;
|
total_in += filesz;
|
||||||
|
|
||||||
if (0==slide) {
|
unsigned o_offset = get_te64(&o_phdr->p_offset);
|
||||||
slide = vaddr - offset;
|
fo->seek(o_offset, SEEK_SET);
|
||||||
}
|
|
||||||
if (fo) {
|
|
||||||
fo->seek(slide + offset, SEEK_SET);
|
|
||||||
fo->write(ibuf, filesz);
|
fo->write(ibuf, filesz);
|
||||||
total_out = filesz + slide + offset; // high-water mark
|
total_out = filesz + o_offset; // high-water mark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set_te64(&phdr->p_offset, slide + offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fo) { // Rewrite Phdrs after sliding
|
|
||||||
fo->seek(sizeof(Elf64_Ehdr), SEEK_SET);
|
|
||||||
fo->rewrite(phdro, e_phnum * sizeof(Elf64_Phdr));
|
|
||||||
}
|
|
||||||
// loader offset
|
// loader offset
|
||||||
fi->seek(xct_off + sizeof(linfo) + sizeof(p_info) + sizeof(b_info) + up4(ph.c_len), SEEK_SET);
|
fi->seek(l_offset, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackLinuxElf64::un_DT_INIT(
|
void PackLinuxElf64::un_DT_INIT(
|
||||||
@@ -4840,7 +4852,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
|||||||
unsigned u_adler = upx_adler32(nullptr, 0);
|
unsigned u_adler = upx_adler32(nullptr, 0);
|
||||||
|
|
||||||
unsigned is_shlib = 0;
|
unsigned is_shlib = 0;
|
||||||
MemBuffer phdro;
|
MemBuffer o_elfhdrs;
|
||||||
Elf64_Phdr const *const dynhdr = elf_find_ptype(Elf64_Phdr::PT_DYNAMIC, phdri, c_phnum);
|
Elf64_Phdr const *const dynhdr = elf_find_ptype(Elf64_Phdr::PT_DYNAMIC, phdri, c_phnum);
|
||||||
if (dynhdr) {
|
if (dynhdr) {
|
||||||
upx_uint64_t dyn_offset = get_te64(&dynhdr->p_offset);
|
upx_uint64_t dyn_offset = get_te64(&dynhdr->p_offset);
|
||||||
@@ -4850,9 +4862,8 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
|||||||
if (!(Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1))) {
|
if (!(Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1))) {
|
||||||
is_shlib = 1;
|
is_shlib = 1;
|
||||||
u_phnum = get_te16(&ehdri.e_phnum);
|
u_phnum = get_te16(&ehdri.e_phnum);
|
||||||
phdro.alloc(u_phnum * sizeof(Elf64_Phdr));
|
o_elfhdrs.alloc(sz_elf_hdrs);
|
||||||
memcpy(phdro, phdri, u_phnum * sizeof(*phdri));
|
un_shlib_1(fo, o_elfhdrs, c_adler, u_adler, dynhdr, orig_file_size, szb_info);
|
||||||
un_shlib_1(fo, (Elf64_Phdr *)(void *)phdro, c_adler, u_adler, dynhdr, orig_file_size, szb_info);
|
|
||||||
*ehdr = ehdri;
|
*ehdr = ehdri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4881,8 +4892,8 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
|||||||
if ((umin64(MAX_ELF_HDR, ph.u_len) - sizeof(Elf64_Ehdr))/sizeof(Elf64_Phdr) < u_phnum) {
|
if ((umin64(MAX_ELF_HDR, ph.u_len) - sizeof(Elf64_Ehdr))/sizeof(Elf64_Phdr) < u_phnum) {
|
||||||
throwCantUnpack("bad compressed e_phnum");
|
throwCantUnpack("bad compressed e_phnum");
|
||||||
}
|
}
|
||||||
phdro.alloc(u_phnum * sizeof(Elf64_Phdr));
|
o_elfhdrs.alloc(sizeof(Elf64_Ehdr) + u_phnum * sizeof(Elf64_Phdr));
|
||||||
memcpy(phdro, 1+ ehdr, u_phnum * sizeof(Elf64_Phdr));
|
memcpy(o_elfhdrs, ehdr, o_elfhdrs.getSize());
|
||||||
#undef MAX_ELF_HDR
|
#undef MAX_ELF_HDR
|
||||||
|
|
||||||
// Decompress each PT_LOAD.
|
// Decompress each PT_LOAD.
|
||||||
@@ -4936,7 +4947,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The gaps between PT_LOAD and after last PT_LOAD
|
// The gaps between PT_LOAD and after last PT_LOAD
|
||||||
phdr = (Elf64_Phdr *)(void *)phdro;
|
phdr = (Elf64_Phdr const *)(1+ (Elf64_Ehdr const *)(void const *)o_elfhdrs);
|
||||||
upx_uint64_t hi_offset(0);
|
upx_uint64_t hi_offset(0);
|
||||||
for (unsigned j = 0; j < u_phnum; ++j) {
|
for (unsigned j = 0; j < u_phnum; ++j) {
|
||||||
if (PT_LOAD64==phdr[j].p_type
|
if (PT_LOAD64==phdr[j].p_type
|
||||||
@@ -4972,7 +4983,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_shlib) {
|
if (is_shlib) {
|
||||||
un_DT_INIT(old_dtinit, (Elf64_Phdr *)(void *)phdro, dynhdr, fo, is_asl);
|
un_DT_INIT(old_dtinit, (Elf64_Phdr *)(1+ (Elf64_Ehdr *)(void *)o_elfhdrs), dynhdr, fo, is_asl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update header with totals
|
// update header with totals
|
||||||
|
|||||||
+1
-1
@@ -272,7 +272,7 @@ protected:
|
|||||||
virtual void unpack(OutputFile *fo);
|
virtual void unpack(OutputFile *fo);
|
||||||
virtual void un_shlib_1(
|
virtual void un_shlib_1(
|
||||||
OutputFile *const fo,
|
OutputFile *const fo,
|
||||||
Elf64_Phdr *const phdro,
|
MemBuffer &o_elfhdrs,
|
||||||
unsigned &c_adler,
|
unsigned &c_adler,
|
||||||
unsigned &u_adler,
|
unsigned &u_adler,
|
||||||
Elf64_Phdr const *const dynhdr,
|
Elf64_Phdr const *const dynhdr,
|
||||||
|
|||||||
Reference in New Issue
Block a user