WIP: un_shlib_1

modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
This commit is contained in:
John Reiser
2021-05-08 11:14:31 -07:00
committed by Markus F.X.J. Oberhumer
parent bd4aca5c12
commit 181c752488
2 changed files with 69 additions and 58 deletions
+68 -57
View File
@@ -785,6 +785,7 @@ PackLinuxElf64::PackLinuxElf64help1(InputFile *f)
}
}
sz_phdrs = e_phnum * e_phentsize;
sz_elf_hdrs = sz_phdrs + sizeof(Elf64_Ehdr);
if (f && Elf64_Ehdr::ET_DYN!=e_type) {
unsigned const len = sz_phdrs + e_phoff;
@@ -4594,7 +4595,7 @@ PackLinuxElf64::unRela64(
void PackLinuxElf64::un_shlib_1(
OutputFile *const fo,
Elf64_Phdr *const phdro,
MemBuffer &o_elfhdrs,
unsigned &c_adler,
unsigned &u_adler,
Elf64_Phdr const *const dynhdr,
@@ -4602,7 +4603,7 @@ void PackLinuxElf64::un_shlib_1(
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);
unsigned const limit_dynhdr = get_te64(&dynhdr->p_offset) + get_te64(&dynhdr->p_filesz);
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
fi->seek(xct_off + sizeof(linfo) + sizeof(p_info), SEEK_SET);
struct b_info hdr;
fi->readx(&hdr, sizeof(hdr)); // Peek at b_info
fi->seek(-(off_t)sizeof(hdr), SEEK_CUR);
ph.c_len = get_te32(&hdr.sz_cpr);
ph.u_len = get_te32(&hdr.sz_unc);
// Decompress first Extent. Old style covers [0, xct_off);
// new style covers just Elf headers: the rest below xct_off is constant!
fi->seek(xct_off, SEEK_SET);
struct {
struct l_info l;
struct p_info p;
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,
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();
// Copy (slide) the remaining PT_LOAD; they are not compressed
Elf64_Phdr *phdr = phdro;
unsigned slide = 0;
int first = 0;
for (unsigned k = 0; k < e_phnum; ++k, ++phdr) {
unsigned type = get_te32(&phdr->p_type);
unsigned vaddr = get_te64(&phdr->p_vaddr);
unsigned offset = get_te64(&phdr->p_offset);
unsigned filesz = get_te64(&phdr->p_filesz);
if (xct_off <= vaddr) {
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->readx(ibuf, filesz);
total_in += filesz;
if (0==slide) {
slide = vaddr - offset;
}
if (fo) {
fo->seek(slide + offset, SEEK_SET);
fo->write(ibuf, filesz);
total_out = filesz + slide + offset; // high-water mark
}
}
}
set_te64(&phdr->p_offset, slide + offset);
// 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);
}
}
if (fo) { // Rewrite Phdrs after sliding
fo->seek(sizeof(Elf64_Ehdr), SEEK_SET);
fo->rewrite(phdro, e_phnum * sizeof(Elf64_Phdr));
// 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
// because relocation processing by rtld might alter their memory image
Elf64_Phdr const *i_phdr = phdri;
Elf64_Phdr const *o_phdr = (Elf64_Phdr const *)(1+ (Elf64_Ehdr const *)(void const *)o_elfhdrs);
for (unsigned k = 0; k < e_phnum; ++k, ++i_phdr, ++o_phdr) {
unsigned type = get_te32(&i_phdr->p_type);
unsigned vaddr = get_te64(&i_phdr->p_vaddr);
unsigned offset = get_te64(&i_phdr->p_offset);
unsigned filesz = get_te64(&i_phdr->p_filesz);
if (xct_off <= vaddr) {
if (PT_LOAD64==type) {
fi->seek(offset, SEEK_SET);
fi->readx(ibuf, filesz);
total_in += filesz;
unsigned o_offset = get_te64(&o_phdr->p_offset);
fo->seek(o_offset, SEEK_SET);
fo->write(ibuf, filesz);
total_out = filesz + o_offset; // high-water mark
}
}
}
// 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(
@@ -4840,7 +4852,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
unsigned u_adler = upx_adler32(nullptr, 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);
if (dynhdr) {
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))) {
is_shlib = 1;
u_phnum = get_te16(&ehdri.e_phnum);
phdro.alloc(u_phnum * sizeof(Elf64_Phdr));
memcpy(phdro, phdri, u_phnum * sizeof(*phdri));
un_shlib_1(fo, (Elf64_Phdr *)(void *)phdro, c_adler, u_adler, dynhdr, orig_file_size, szb_info);
o_elfhdrs.alloc(sz_elf_hdrs);
un_shlib_1(fo, o_elfhdrs, c_adler, u_adler, dynhdr, orig_file_size, szb_info);
*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) {
throwCantUnpack("bad compressed e_phnum");
}
phdro.alloc(u_phnum * sizeof(Elf64_Phdr));
memcpy(phdro, 1+ ehdr, u_phnum * sizeof(Elf64_Phdr));
o_elfhdrs.alloc(sizeof(Elf64_Ehdr) + u_phnum * sizeof(Elf64_Phdr));
memcpy(o_elfhdrs, ehdr, o_elfhdrs.getSize());
#undef MAX_ELF_HDR
// Decompress each PT_LOAD.
@@ -4936,7 +4947,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
}
// 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);
for (unsigned j = 0; j < u_phnum; ++j) {
if (PT_LOAD64==phdr[j].p_type
@@ -4972,7 +4983,7 @@ void PackLinuxElf64::unpack(OutputFile *fo)
}
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
+1 -1
View File
@@ -272,7 +272,7 @@ protected:
virtual void unpack(OutputFile *fo);
virtual void un_shlib_1(
OutputFile *const fo,
Elf64_Phdr *const phdro,
MemBuffer &o_elfhdrs,
unsigned &c_adler,
unsigned &u_adler,
Elf64_Phdr const *const dynhdr,