1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Put upx stub loader at high end of ELF output file on linux,

and allow for block-by-block specification of filter and parameters.
	linker.cpp linker.h mem.cpp mem.h p_elf.h
	p_lx_elf.cpp p_lx_elf.h
	p_lx_exc.cpp p_lx_exc.h
	p_lx_sh.cpp  p_lx_sh.h
	p_unix.cpp p_unix.h
	packer.cpp packer.h
	stub/fold_elf86.asm stub/fold_exec86.asm stub/fold_sh86.asm
	stub/l_lx_elf.c  stub/l_lx_elf86.asm  stub/l_lx_elf86.lds
	stub/l_lx_exec.c stub/l_lx_exec86.asm stub/l_lx_exec86.lds
	stub/l_lx_sh.c   stub/l_lx_sh86.asm   stub/l_lx_sh86.lds
	stub/linux.hh

committer: jreiser <jreiser> 981084316 +0000
This commit is contained in:
John Reiser 2001-02-02 03:25:16 +00:00
parent 9005e50049
commit 40fddf1715
28 changed files with 797 additions and 614 deletions

View File

@ -53,6 +53,7 @@ Linker::Linker(const void *pdata, int plen, int pinfo)
oloader = new char[plen];
olen = 0;
align_hack = 0;
align_offset = 0;
info = pinfo;
njumps = nsections = frozen = 0;
jumps = new jump[200];
@ -100,6 +101,16 @@ Linker::~Linker()
}
void Linker::setLoaderAlignOffset(int offset)
{
align_offset = offset;
}
static int hex(char c)
{
return (c & 0xf) + (c > '9' ? 9 : 0);
}
int Linker::addSection(const char *sect)
{
int ic;
@ -108,14 +119,13 @@ int Linker::addSection(const char *sect)
if (*sect == '+') // alignment
{
if (sect[1] == '0')
align_hack = olen;
align_hack = olen + align_offset;
else
{
ic = (sect[1] & 0xf) + (sect[1] > '9' ? 9 : 0);
ic = (ic + (sect[2] & 0xf) + (sect[2] > '9' ? 9 : 0)
- (olen - align_hack) % ic) % ic;
memset(oloader+olen,sect[3] == 'C' ? 0x90 : 0,ic);
olen += ic;
unsigned j = hex(sect[1]);
j = (hex(sect[2]) - ((olen + align_offset) - align_hack) ) % j;
memset(oloader+olen, (sect[3] == 'C' ? 0x90 : 0), j);
olen += j;
}
}
else

View File

@ -40,6 +40,7 @@ public:
const char *getLoader(int *llen);
int getSection(const char *name, int *slen) const;
int getLoaderSize() const { return olen; }
void setLoaderAlignOffset(int phase);
protected:
// little endian
@ -59,6 +60,7 @@ private:
int nsections;
int frozen;
int align_hack;
int align_offset;
private:
// disable copy and assignment

View File

@ -47,15 +47,6 @@ MemBuffer::~MemBuffer()
this->free();
}
MemBufferIO::MemBufferIO(unsigned size) :
MemBuffer(size)
{
}
MemBufferIO::~MemBufferIO()
{
}
void MemBuffer::free()
{
if (alloc_ptr)
@ -75,39 +66,6 @@ unsigned MemBuffer::getSize() const
}
unsigned MemBufferIO::seek(unsigned offset, int whence)
{
switch (whence) {
default: {
assert(false);
} break;
case SEEK_SET: {
assert(offset<=alloc_size);
ptr = offset + alloc_ptr;
} break;
case SEEK_CUR: {
assert((offset + (ptr - alloc_ptr))<=alloc_size);
ptr += offset;
} break;
case SEEK_END: {
assert((offset + alloc_size)<=alloc_size);
ptr = offset + alloc_size + alloc_ptr;
} break;
}
return ptr - alloc_ptr;
}
unsigned MemBufferIO::write(void const *data, unsigned size)
{
unsigned const avail = getSize();
unsigned const len = UPX_MIN(size, avail);
if (data!=ptr) {
memmove(ptr, data, len);
}
ptr += len;
return len;
}
void MemBuffer::alloc(unsigned size, unsigned base_offset)
{
#if 0

View File

@ -72,15 +72,6 @@ private:
//static void operator delete[] (void *) {}
};
class MemBufferIO : public MemBuffer {
public:
MemBufferIO(unsigned size=0);
~MemBufferIO();
unsigned seek(unsigned offset, int whence); // returns new position
unsigned write(void const *data, unsigned size); // returns xfer count
};
#endif /* already included */

View File

@ -67,7 +67,11 @@ struct Elf_LE32_Phdr
LE32 p_align; /* Segment alignment */
// Values for p_type
enum { PT_LOAD = 1 }; /* Loadable program segment */
enum {
PT_LOAD = 1, /* Loadable program segment */
PT_DYNAMIC = 2, /* Dynamic linking information */
PT_PHDR = 6 /* Entry for header table itself */
};
// Values for p_flags
enum { PF_X = (1 << 0) }; /* Segment is executable */
@ -76,6 +80,18 @@ struct Elf_LE32_Phdr
};
struct Elf_LE32_Dyn
{
LE32 d_tag;
LE32 d_val;
enum { // tags
DT_NULL = 0, /* End flag */
DT_NEEDED = 1, /* Name of needed library */
DT_STRTAB = 5, /* String table */
DT_STRSZ = 10 /* Sizeof string table */
};
};
#endif /* already included */

View File

@ -80,35 +80,11 @@ PackLinuxI386elf::buildLoader(const Filter *ft)
{
return buildLinuxLoader(
linux_i386elf_loader, sizeof(linux_i386elf_loader),
linux_i386elf_fold, sizeof(linux_i386elf_fold),
ft, getbrk(phdri, ehdri.e_phnum) );
linux_i386elf_fold, sizeof(linux_i386elf_fold), ft );
}
void PackLinuxI386elf::updateLoader(OutputFile *fo)
{
#define PAGE_MASK (~0<<12)
upx_byte *const ptr = const_cast<upx_byte *>(getLoader());
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(sizeof(Elf_LE32_Ehdr) + ptr);
off_t const totlen = fo->getBytesWritten();
phdro->p_filesz = totlen;
// pre-calculate for benefit of runtime disappearing act via munmap()
phdro->p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
patchLoaderChecksum();
#undef PAGE_MASK
}
void PackLinuxI386elf::patchLoader()
{
unsigned char *const ptr = const_cast<unsigned char *>(getLoader());
lsize = getLoaderSize();
assert(lsize > 128 && lsize < 4096);
patchVersion(ptr, lsize);
patchLoaderChecksum();
}
void PackLinuxI386elf::patchLoader() { }
bool PackLinuxI386elf::canPack()
@ -146,17 +122,12 @@ bool PackLinuxI386elf::canPack()
throwCantPack("invalid Phdr p_offset; try `--force-execve'");
return false;
}
#if 1
// FIXME: what about these checks ?
if (phdr->p_vaddr != 0x08048000) {
// detect possible conflict upon invocation
if (phdr->p_vaddr < (unsigned)(0x400000 + file_size)
|| phdr->p_paddr < (unsigned)(0x400000 + file_size) ) {
throwCantPack("invalid Phdr p_vaddr; try `--force-execve'");
return false;
}
if (phdr->p_paddr != 0x08048000) {
throwCantPack("invalid Phdr p_paddr; try `--force-execve'");
return false;
}
#endif
exetype = 1;
break;
}
@ -165,100 +136,105 @@ bool PackLinuxI386elf::canPack()
return super::canPack();
}
struct cprBlkHdr {
unsigned sz_unc; // uncompressed size (0 means EOF)
unsigned sz_cpr; // (compressed_size<<8) | cto8
};
void PackLinuxI386elf::packExtent(
Extent const &x,
unsigned &total_in,
unsigned &total_out,
Filter *ft
Filter *ft,
OutputFile *fo
)
{
fi->seek(x.offset, SEEK_SET);
for (off_t rest = x.size; 0 != rest; )
{
for (off_t rest = x.size; 0 != rest; ) {
int const strategy = getStrategy(*ft);
int l = fi->readx(ibuf, UPX_MIN(rest, (off_t)blocksize));
if (l == 0)
if (l == 0) {
break;
}
rest -= l;
// Note: compression for a block can fail if the
// file is e.g. blocksize + 1 bytes long
// compress
unsigned char *const hdrptr = obuf;
obuf.seek(sizeof(cprBlkHdr), SEEK_CUR);
ph.u_len = l;
ph.overlap_overhead = 0;
unsigned end_u_adler;
if (ft) {
// compressWithFilters() updates u_adler _inside_ compress();
// that is, AFTER filtering. We want BEFORE filtering,
// so that decompression checks the end-to-end checksum.
end_u_adler = upx_adler32(ph.u_adler, ibuf, ph.u_len);
ft->buf_len = l;
compressWithFilters(ft, OVERHEAD, ((opt->filter > 0) ? -2 : 2));
compressWithFilters(ft, OVERHEAD, strategy);
}
else {
(void) compress(ibuf, obuf); // ignore return value
}
if (ph.c_len < ph.u_len)
{
if (ph.c_len < ph.u_len) {
ph.overlap_overhead = OVERHEAD;
if (!testOverlappingDecompression(obuf, ph.overlap_overhead))
if (!testOverlappingDecompression(obuf, ph.overlap_overhead)) {
throwNotCompressible();
}
else
{
}
else {
ph. c_len = ph.u_len;
// must update checksum of compressed data
ph.c_adler = upx_adler32(ph.c_adler, ibuf, ph.u_len);
}
// write block sizes
set_native32(0+hdrptr, ph.u_len);
set_native32(4+hdrptr, (ph.c_len<<8) | ph.filter_cto);
b_info tmp; memset(&tmp, 0, sizeof(tmp));
set_native32(&tmp.sz_unc, ph.u_len);
set_native32(&tmp.sz_cpr, ph.c_len);
tmp.b_method = ph.method;
if (ft) {
tmp.b_ftid = ft->id;
tmp.b_cto8 = ft->cto;
}
fo->write(&tmp, sizeof(tmp));
ph.b_len += sizeof(b_info);
// write compressed data
if (ph.c_len < ph.u_len)
{
obuf.write(obuf, ph.c_len);
// FIXME: obuf is not discardable!
// verifyOverlappingDecompression();
if (ph.c_len < ph.u_len) {
fo->write(obuf, ph.c_len);
// Checks ph.u_adler after decompression but before unfiltering
verifyOverlappingDecompression();
}
else {
fo->write(ibuf, ph.u_len);
}
else
obuf.write(ibuf, ph.u_len);
if (ft) {
ph.u_adler = end_u_adler;
}
total_in += ph.u_len;
total_out += ph.c_len;
}
}
void PackLinuxI386elf::pack(OutputFile *fo)
void PackLinuxI386elf::pack1(OutputFile *fo, Filter &)
{
// set options
opt->unix.blocksize = blocksize = file_size;
progid = 0; // not used
fi->seek(0, SEEK_SET);
fi->readx(&ehdri, sizeof(ehdri));
assert(ehdri.e_phoff == sizeof(Elf_LE32_Ehdr)); // checked by canPack()
off_t const sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize;
sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize;
phdri = new Elf_LE32_Phdr[ehdri.e_phnum];
fi->seek(ehdri.e_phoff, SEEK_SET);
fi->readx(phdri, sz_phdrs);
// init compression buffers
ibuf.alloc(blocksize);
obuf.allocForCompression(blocksize);
{
p_info hbuf;
set_native32(&hbuf.p_progid, progid);
set_native32(&hbuf.p_filesize, file_size);
set_native32(&hbuf.p_blocksize, blocksize);
obuf.write(&hbuf, sizeof(hbuf));
generateElfHdr(fo, linux_i386elf_fold, phdri, ehdri.e_phnum,
getbrk(phdri, ehdri.e_phnum) );
}
void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft)
{
Extent x;
unsigned k;
@ -294,12 +270,11 @@ void PackLinuxI386elf::pack(OutputFile *fo)
x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs;
{
int const old_level = ph.level; ph.level = 10;
packExtent(x, total_in, total_out, 0);
packExtent(x, total_in, total_out, 0, fo);
ph.level = old_level;
}
ui_pass = 0;
Filter ft(ph.level);
ft.addvalue = 0;
nx = 0;
@ -319,53 +294,22 @@ void PackLinuxI386elf::pack(OutputFile *fo)
}
packExtent(x, total_in, total_out,
((Elf_LE32_Phdr::PF_X & phdri[k].p_flags)
? &ft : 0 ) );
? &ft : 0 ), fo );
++nx;
}
if (ptload0hi < ptload1lo) { // alignment hole?
x.offset = ptload0hi;
x.size = ptload1lo - ptload0hi;
packExtent(x, total_in, total_out, 0);
packExtent(x, total_in, total_out, 0, fo);
}
if ((off_t)total_in < file_size) { // non-PT_LOAD stuff
x.offset = total_in;
x.size = file_size - total_in;
packExtent(x, total_in, total_out, 0);
packExtent(x, total_in, total_out, 0, fo);
}
if ((off_t)total_in != file_size)
throwEOFException();
// write block end marker (uncompressed size 0)
set_native32(obuf, 0);
obuf.write(obuf, 4);
// update header with totals
ph.u_len = total_in;
ph.c_len = total_out;
upx_byte const *p = getLoader();
lsize = getLoaderSize();
patchFilter32(const_cast<upx_byte *>(p), lsize, &ft);
fo->write(p, lsize);
unsigned pos = obuf.seek(0, SEEK_CUR);
fo->write(obuf - pos, pos);
// write packheader
writePackHeader(fo);
// write overlay offset (needed for decompression)
set_native32(obuf, lsize);
fo->write(obuf, 4);
updateLoader(fo);
fo->seek(0, SEEK_SET);
fo->rewrite(p, lsize);
// finally check the compression ratio
if (!checkFinalCompressionRatio(fo))
throwNotCompressible();
}
@ -376,11 +320,11 @@ void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo,
)
{
while (wanted) {
fi->readx(ibuf, 8);
int const sz_unc = ph.u_len = get_native32(ibuf+0);
unsigned const tmp = get_native32(ibuf+4);
int const sz_cpr = ph.c_len = tmp>>8;
ph.filter_cto = tmp<<24;
b_info hdr;
fi->readx(&hdr, sizeof(hdr));
int const sz_unc = ph.u_len = get_native32(&hdr.sz_unc);
int const sz_cpr = ph.c_len = get_native32(&hdr.sz_cpr);
ph.filter_cto = hdr.b_cto8;
if (sz_unc == 0) { // must never happen while 0!=wanted
throwCompressedDataViolation();
@ -438,11 +382,11 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
throwCantUnpack("file header corrupted");
ibuf.alloc(blocksize + OVERHEAD);
fi->readx(ibuf, 2*4);
ph.u_len = get_native32(0+ibuf);
unsigned const tmp = get_native32(4+ibuf);
ph.c_len = tmp>>8;
ph.filter_cto = tmp<<24;
b_info bhdr;
fi->readx(&bhdr, sizeof(bhdr));
ph.u_len = get_native32(&bhdr.sz_unc);
ph.c_len = get_native32(&bhdr.sz_cpr);
ph.filter_cto = bhdr.b_cto8;
// Uncompress Ehdr and Phdrs.
fi->readx(ibuf, ph.c_len);
@ -456,7 +400,7 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
// decompress PT_LOAD
bool first_PF_X = true;
fi->seek(- (off_t) (2*4 + ph.c_len), SEEK_CUR);
fi->seek(- (off_t) (sizeof(bhdr) + ph.c_len), SEEK_CUR);
for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) {
if (PT_LOAD==phdr->p_type) {
if (0==ptload0hi) {
@ -493,12 +437,12 @@ void PackLinuxI386elf::unpack(OutputFile *fo)
}
// check for end-of-file
fi->readx(ibuf, 2*4);
unsigned const sz_unc = ph.u_len = get_native32(ibuf+0);
fi->readx(&bhdr, sizeof(bhdr));
unsigned const sz_unc = ph.u_len = get_native32(&bhdr.sz_unc);
if (sz_unc == 0) { // uncompressed size 0 -> EOF
// note: magic is always stored le32
unsigned const sz_cpr = get_le32(ibuf+4);
unsigned const sz_cpr = get_le32(&bhdr.sz_cpr);
if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic
throwCompressedDataViolation();
}

View File

@ -47,7 +47,6 @@ public:
virtual const int *getFilters() const;
virtual int buildLoader(const Filter *);
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
virtual bool canPack();
@ -60,22 +59,20 @@ protected:
off_t size;
};
virtual void packExtent(Extent const &x,
unsigned &total_in, unsigned &total_out, Filter *);
unsigned &total_in, unsigned &total_out, Filter *, OutputFile *);
virtual void unpackExtent(unsigned wanted, OutputFile *fo,
unsigned &total_in, unsigned &total_out,
unsigned &c_adler, unsigned &u_adler, bool first_PF_X);
protected:
#if 0 //{
virtual const upx_byte *getLoader() const;
virtual int getLoaderSize() const;
#endif //}
virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data
virtual void patchLoader();
virtual void updateLoader(OutputFile *);
Elf_LE32_Ehdr ehdri; // from input file
Elf_LE32_Phdr *phdri; // for input file
unsigned sz_phdrs; // sizeof Phdr[]
};

View File

@ -38,6 +38,11 @@
#include "p_lx_exc.h"
#define PT_LOAD Elf_LE32_Phdr::PT_LOAD
#define PT_DYNAMIC Elf_LE32_Phdr::PT_DYNAMIC
#define DT_NULL Elf_LE32_Dyn::DT_NULL
#define DT_NEEDED Elf_LE32_Dyn::DT_NEEDED
#define DT_STRTAB Elf_LE32_Dyn::DT_STRTAB
#define DT_STRSZ Elf_LE32_Dyn::DT_STRSZ
/*************************************************************************
@ -75,11 +80,225 @@ PackLinuxI386::getFilters() const
return filters;
}
struct cprElfhdr {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[2];
struct PackUnix::l_info linfo;
};
Elf_LE32_Phdr const *
PackLinuxI386::find_DYNAMIC(Elf_LE32_Phdr const *phdr, unsigned n)
{
if (n) do if (PT_DYNAMIC==phdr->p_type) {
return phdr;
} while (++phdr, 0!=--n);
return 0;
}
unsigned
PackLinuxI386::find_file_offset(
unsigned const vaddr,
Elf_LE32_Phdr const *phdr,
unsigned e_phnum
)
{
if (e_phnum) do {
unsigned t = vaddr - phdr->p_vaddr;
if (t < phdr->p_memsz) {
return t + phdr->p_offset;
}
} while (++phdr, 0!=--e_phnum);
return ~0u;
}
void
PackLinuxI386::generateElfHdr(
OutputFile *const fo,
void const *const proto,
Elf_LE32_Phdr const *const phdr0,
unsigned e_phnum,
unsigned const brka
)
{
cprElfHdr1 *const h1 = (cprElfHdr1 *)&elfout;
cprElfHdr2 *const h2 = (cprElfHdr2 *)&elfout;
cprElfHdr3 *const h3 = (cprElfHdr3 *)&elfout;
memcpy(h2, proto, sizeof(*h2));
assert(h2->ehdr.e_phoff == sizeof(Elf_LE32_Ehdr));
assert(h2->ehdr.e_shoff == 0);
assert(h2->ehdr.e_ehsize == sizeof(Elf_LE32_Ehdr));
assert(h2->ehdr.e_phentsize == sizeof(Elf_LE32_Phdr));
assert(h2->ehdr.e_shnum == 0);
#if 0 //{
unsigned identsize;
char const *const ident = identstr(identsize);
#endif //}
h2->phdr[0].p_filesz = sizeof(*h2); // + identsize;
h2->phdr[0].p_memsz = h2->phdr[0].p_filesz;
// Info for OS kernel to set the brk()
if (brka) {
h2->phdr[1].p_type = PT_LOAD; // be sure
h2->phdr[1].p_offset = 0xfff&brka;
h2->phdr[1].p_vaddr = brka;
h2->phdr[1].p_paddr = brka;
h2->phdr[1].p_filesz = 0;
h2->phdr[1].p_memsz = 0;
}
if (ph.format==UPX_F_LINUX_i386 ) {
assert(h1->ehdr.e_phnum==1);
memset(&h1->linfo, 0, sizeof(h1->linfo));
fo->write(h1, sizeof(*h1));
}
else if (ph.format==UPX_F_LINUX_ELF_i386) {
int const j = ((char *)&h3->phdr[2]) - (char *)h3;
memcpy(&h3->phdr[2], j + (char const *)proto, sizeof(h3->phdr[2]));
assert(h3->ehdr.e_phnum==3);
memset(&h3->linfo, 0, sizeof(h3->linfo));
fo->write(h3, sizeof(*h3));
}
else if (ph.format==UPX_F_LINUX_SH_i386) {
assert(h2->ehdr.e_phnum==1);
h2->ehdr.e_phnum = 2;
memset(&h2->linfo, 0, sizeof(h2->linfo));
fo->write(h2, sizeof(*h2));
}
else {
assert(false); // unknown ph.format, PackUnix::generateElfHdr
}
Elf_LE32_Phdr const *const phdrdyn = find_DYNAMIC(phdr0, e_phnum);
if (phdrdyn) { // propagate DT_NEEDED
MemBuffer dynhdr(phdrdyn->p_memsz);
fi->seek(phdrdyn->p_offset, SEEK_SET);
fi->read(dynhdr, phdrdyn->p_memsz);
unsigned strtabx = ~0u;
unsigned strsz = 0;
int j;
Elf_LE32_Dyn const *p = (Elf_LE32_Dyn const *)(unsigned char *)dynhdr;
int so_needed = 0;
for (j = phdrdyn->p_memsz / sizeof(*p); --j>=0; ++p) {
if (p->d_tag==DT_NEEDED) {
so_needed++;
}
if (p->d_tag==DT_STRTAB) {
strtabx = find_file_offset(p->d_val, phdr0, e_phnum);
}
if (p->d_tag==DT_STRSZ) {
strsz= p->d_val;
}
}
if (so_needed) {
assert(0!=strsz && ~0u!=strtabx);
MemBuffer strtab(strsz);
fi->seek(strtabx, SEEK_SET);
fi->read(strtab, strsz);
int c_needed = 1; // index 0 is reserved
p = (Elf_LE32_Dyn const *)(unsigned char *)dynhdr;
for (j = phdrdyn->p_memsz / sizeof(*p); --j>=0; ++p) {
if (p->d_tag==DT_NEEDED) {
c_needed += 1+ strlen(p->d_val + strtab);
}
}
MemBuffer newtab(c_needed);
unsigned char *cp = newtab;
*cp++ = 0;
p = (Elf_LE32_Dyn const *)(unsigned char *)dynhdr;
for (j = phdrdyn->p_memsz / sizeof(*p); --j>=0; ++p) {
if (p->d_tag==DT_NEEDED) {
unsigned char const *const str = p->d_val + strtab;
unsigned const len = 1+ strlen(str);
memcpy(cp, str, len);
cp += len;
}
}
Elf_LE32_Dyn outdyn[3 + so_needed], *q = &outdyn[0];
q->d_tag = DT_STRSZ;
q->d_val = c_needed; // + identsize;
++q;
q->d_tag = DT_STRTAB;
q->d_val = sizeof(*h3) + sizeof(outdyn) + h3->phdr[0].p_vaddr;
++q;
cp = 1+ newtab;
for (j= so_needed; --j>=0; ++q) {
q->d_tag = DT_NEEDED; q->d_val = cp - newtab;
cp += 1+ strlen(cp);
}
q->d_tag = DT_NULL; q->d_val = 0;
h3->phdr[2].p_type = PT_DYNAMIC;
h3->phdr[2].p_offset = sizeof(*h3);
h3->phdr[2].p_vaddr = sizeof(*h3) + h3->phdr[0].p_vaddr;
h3->phdr[2].p_paddr = h3->phdr[2].p_vaddr;
h3->phdr[2].p_filesz = sizeof(outdyn) + c_needed; // + identsize;
h3->phdr[2].p_memsz = h3->phdr[2].p_filesz;
h3->phdr[2].p_flags = Elf_LE32_Phdr::PF_R;
h3->phdr[2].p_align = 4;
pt_dynamic.alloc(h3->phdr[2].p_filesz);
j = 0;
memcpy(j + pt_dynamic, &outdyn[0], sizeof(outdyn));
j += sizeof(outdyn);
memcpy(j + pt_dynamic, newtab, c_needed);
j += c_needed;
#if 0 //{
memcpy(j + pt_dynamic, ident, identsize);
// FIXME ?? patchVersion(j + pt_dynamic, identsize);
j += identsize;
#endif //}
sz_dynamic = j;
#if 0 //{ debugging: see the results early
fo->seek(0, SEEK_SET);
fo->write(h3, sizeof(*h3));
#endif //}
fo->write(pt_dynamic, sz_dynamic);
}
}
}
void
PackLinuxI386::pack1(OutputFile *fo, Filter &)
{
// create a pseudo-unique program id for our paranoid stub
progid = getRandomId();
generateElfHdr(fo, linux_i386exec_fold, 0, 0, 0);
}
void
PackLinuxI386::pack4(OutputFile *fo, Filter &ft)
{
overlay_offset = sizeof(elfout.ehdr) +
(elfout.ehdr.e_phentsize * elfout.ehdr.e_phnum) +
sizeof(l_info) +
((elfout.ehdr.e_phnum==3) ? elfout.phdr[2].p_memsz : 0) ;
super::pack4(fo, ft); // write PackHeader and overlay_offset
elfout.phdr[0].p_filesz = fo->getBytesWritten();
#define PAGE_MASK (~0<<12)
// pre-calculate for benefit of runtime disappearing act via munmap()
elfout.phdr[0].p_memsz = PAGE_MASK & (~PAGE_MASK + elfout.phdr[0].p_filesz);
#undef PAGE_MASK
// rewrite Elf header
fo->seek(0, SEEK_SET);
fo->rewrite(&elfout, sizeof(elfout.ehdr) +
elfout.ehdr.e_phnum * sizeof(elfout.phdr[0]) +
sizeof(l_info) );
}
static unsigned
umax(unsigned a, unsigned b)
{
if (a <= b) {
return b;
}
return a;
}
int
PackLinuxI386::buildLinuxLoader(
@ -87,52 +306,22 @@ PackLinuxI386::buildLinuxLoader(
unsigned const szproto,
upx_byte const *const fold,
unsigned const szfold,
Filter const *ft,
unsigned const brka
Filter const *ft
)
{
initLoader(proto, szproto);
struct cprElfhdr elfhdr = *(struct cprElfhdr const *)fold;
memset(&elfhdr.linfo, 0, sizeof(elfhdr.linfo));
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
unsigned const fold_hdrlen = umax(0x80, sizeof(hf->ehdr) +
hf->ehdr.e_phentsize * hf->ehdr.e_phnum + sizeof(l_info) );
struct b_info h; memset(&h, 0, sizeof(h));
h.sz_unc = szfold - fold_hdrlen;
h.b_method = ph.method;
h.b_ftid = ph.filter;
h.b_cto8 = ph.filter_cto;
unsigned char const *const uncLoader = fold_hdrlen + fold;
// Info for OS kernel to set the brk()
if (brka) {
assert(ph.format==UPX_F_LINUX_ELF_i386
|| ph.format==UPX_F_LINUX_SH_i386 );
if (ph.format==UPX_F_LINUX_SH_i386) {
assert(elfhdr.ehdr.e_phnum==1);
elfhdr.ehdr.e_phnum = 2;
}
elfhdr.phdr[1].p_offset = 0xfff&brka;
elfhdr.phdr[1].p_vaddr = brka;
elfhdr.phdr[1].p_paddr = brka;
elfhdr.phdr[1].p_filesz = 0;
elfhdr.phdr[1].p_memsz = 0;
}
// The beginning of our loader consists of a elf_hdr (52 bytes) and
// two sections elf_phdr (2 * 32 byte), so we have 12 free bytes
// from offset 116 to the program start at offset 128.
assert(elfhdr.ehdr.e_phoff == sizeof(Elf_LE32_Ehdr));
assert(elfhdr.ehdr.e_shoff == 0);
assert(elfhdr.ehdr.e_ehsize == sizeof(Elf_LE32_Ehdr));
assert(elfhdr.ehdr.e_phentsize == sizeof(Elf_LE32_Phdr));
assert(elfhdr.ehdr.e_phnum == (unsigned)(1+ (0!=brka)));
assert(elfhdr.ehdr.e_shnum == 0);
linker->addSection("ELFHEADX", (unsigned char const *)&elfhdr, sizeof(elfhdr));
addLoader("ELFHEADX", 0);
struct {
upx_uint sz_unc; // uncompressed
upx_uint sz_cpr; // compressed
} h = {
szfold - sizeof(elfhdr), 0
};
unsigned char const *const uncLoader = (unsigned char const *)(1+
(struct cprElfhdr const *)fold );
unsigned char *const cprLoader = new unsigned char[sizeof(h) + h.sz_unc];
int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &h.sz_cpr,
NULL, ph.method, 10, NULL, NULL );
if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc)
@ -143,7 +332,21 @@ PackLinuxI386::buildLinuxLoader(
n_mru = ft->n_mru;
addLoader("IDENTSTR", 0);
// Here is a quick summary of the format of the output file:
linker->setLoaderAlignOffset(
// Elf32_Edhr
sizeof(elfout.ehdr) +
// Elf32_Phdr: 1 for exec86, 2 for sh86, 3 for elf86
(elfout.ehdr.e_phentsize * elfout.ehdr.e_phnum) +
// checksum UPX! lsize version format
sizeof(l_info) +
// PT_DYNAMIC with DT_NEEDED "forwarded" from original file
((elfout.ehdr.e_phnum==3) ? elfout.phdr[2].p_memsz : 0) +
// p_progid, p_filesize, p_blocksize
sizeof(p_info) +
// compressed data
ph.b_len + ph.c_len );
// entry to stub
addLoader("LEXEC000", 0);
if (ft->id) {
@ -206,21 +409,18 @@ PackLinuxI386::buildLinuxLoader(
}
}
addLoader("IDENTSTR", 0);
addLoader("LEXEC020", 0);
addLoader("FOLDEXEC", 0);
struct Elf_LE32_Ehdr *const ldrEhdr =
(struct Elf_LE32_Ehdr *)const_cast<unsigned char *>(getLoader());
unsigned e_entry = getLoaderSectionStart("LEXEC000");
ldrEhdr->e_entry = e_entry + elfhdr.phdr[0].p_vaddr;
char *ptr_cto = e_entry + (char *)ldrEhdr;
int sz_cto = getLoaderSize() - e_entry;
char *ptr_cto = (char *)const_cast<unsigned char *>(getLoader());
int sz_cto = getLoaderSize();
if (0x20==(ft->id & 0xF0) || 0x30==(ft->id & 0xF0)) { // push byte '?' ; cto8
patch_le16(ptr_cto, sz_cto, "\x6a?", 0x6a + (ft->cto << 8));
}
// PackHeader and overlay_offset at the end of the output file,
// after the compressed data.
// FIXME ?? patchVersion((char *)ldrEhdr, e_entry);
return getLoaderSize();
}
@ -247,12 +447,12 @@ PackLinuxI386::buildLoader(Filter const *ft)
// filter
optimizeFilter(&fold_ft, buf, sz_fold);
bool success = fold_ft.filter(buf + sizeof(cprElfhdr), sz_fold - sizeof(cprElfhdr));
bool success = fold_ft.filter(buf + sizeof(cprElfHdr2), sz_fold - sizeof(cprElfHdr2));
(void)success;
return buildLinuxLoader(
linux_i386exec_loader, sizeof(linux_i386exec_loader),
buf, sz_fold, ft, 0 );
buf, sz_fold, ft );
}
int PackLinuxI386::getLoaderPrefixSize() const
@ -366,15 +566,14 @@ bool PackLinuxI386::canPack()
}
void PackLinuxI386::patchLoader()
{
}
void PackLinuxI386::patchLoader() { }
void PackLinuxI386::patchLoaderChecksum()
{
unsigned char *const ptr = const_cast<unsigned char *>(getLoader());
l_info *const lp = (l_info *)(ptr + getLoaderPrefixSize());
l_info *const lp = (l_info *)(sizeof(elfout.ehdr) +
(elfout.ehdr.e_phnum * elfout.ehdr.e_phentsize) + (char *)&elfout );
// checksum for loader + p_info
lp->l_checksum = 0;
lp->l_magic = UPX_ELF_MAGIC;
@ -383,36 +582,14 @@ void PackLinuxI386::patchLoaderChecksum()
lp->l_format = (unsigned char) ph.format;
// INFO: lp->l_checksum is currently unused
unsigned adler = upx_adler32(0,NULL,0);
adler = upx_adler32(adler, ptr, lsize + sizeof(p_info));
adler = upx_adler32(adler, ptr, lsize);
lp->l_checksum = adler;
}
void PackLinuxI386::updateLoader(OutputFile *fo)
{
#define PAGE_MASK (~0<<12)
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)const_cast<upx_byte *>(getLoader());
Elf_LE32_Phdr *const phdr = (Elf_LE32_Phdr *)(1+ehdr);
ehdr->e_phnum = 2;
phdr->p_filesz = lsize;
// phdr->p_memsz is the decompressed size
assert(lsize > 128 && lsize < 4096);
// The first Phdr maps the stub (instructions, data, bss) rwx.
// The second Phdr maps the overlay r--,
// to defend against /usr/bin/strip removing the overlay.
Elf_LE32_Phdr *const phdro = 1+phdr;
phdro->p_type = PT_LOAD;
phdro->p_offset = lsize;
phdro->p_paddr = phdro->p_vaddr = 0x00400000 + (lsize &~ PAGE_MASK);
phdro->p_memsz = phdro->p_filesz = fo->getBytesWritten() - lsize;
phdro->p_flags = phdro->PF_R;
phdro->p_align = (unsigned) (-PAGE_MASK);
patchLoaderChecksum();
#undef PAGE_MASK
elfout.ehdr.e_entry = fo->getBytesWritten() + elfout.phdr[0].p_vaddr;
}

View File

@ -39,6 +39,13 @@ class PackLinuxI386 : public PackUnixLe32
typedef PackUnixLe32 super;
public:
PackLinuxI386(InputFile *f) : super(f) { }
virtual void generateElfHdr(
OutputFile *,
void const *proto,
Elf_LE32_Phdr const *const phdr0,
unsigned e_phnum,
unsigned brka
);
virtual int getFormat() const { return UPX_F_LINUX_i386; }
virtual const char *getName() const { return "linux/386"; }
virtual const int *getCompressionMethods(int method, int level) const;
@ -48,6 +55,18 @@ public:
virtual bool canPack();
protected:
virtual void pack1(OutputFile *, Filter &); // generate executable header
// virtual void pack2(OutputFile *, Filter &); // append compressed data
// virtual void pack3(OutputFile *, Filter &); // append loader
virtual void pack4(OutputFile *, Filter &); // append PackHeader
unsigned find_file_offset(
unsigned vaddr,
Elf_LE32_Phdr const *phdr,
unsigned e_phnum
);
Elf_LE32_Phdr const *find_DYNAMIC(Elf_LE32_Phdr const *phdr, unsigned n);
// loader util
virtual int getLoaderPrefixSize() const;
virtual int buildLinuxLoader(
@ -55,16 +74,9 @@ protected:
unsigned const szproto,
upx_byte const *const fold, // linked assembly + C section
unsigned const szfold,
Filter const *ft,
unsigned const brka
Filter const *ft
);
struct cprElfhdr {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[2];
struct PackUnix::l_info linfo;
};
// patch util
virtual void patchLoader();
virtual void patchLoaderChecksum();
@ -79,6 +91,25 @@ protected:
};
unsigned n_mru;
struct cprElfHdr1 {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[1];
struct PackUnix::l_info linfo;
};
struct cprElfHdr2 {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[2];
struct PackUnix::l_info linfo;
};
struct cprElfHdr3 {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[3];
struct PackUnix::l_info linfo;
};
cprElfHdr3 elfout;
};

View File

@ -78,17 +78,15 @@ PackLinuxI386sh::buildLoader(Filter const *ft)
// filter
optimizeFilter(&fold_ft, buf, sz_fold);
bool success = fold_ft.filter(buf + sizeof(cprElfhdr), sz_fold - sizeof(cprElfhdr));
bool success = fold_ft.filter(buf + sizeof(cprElfHdr2), sz_fold - sizeof(cprElfHdr2));
(void)success;
return buildLinuxLoader(
linux_i386sh_loader, sizeof(linux_i386sh_loader),
buf, sz_fold, ft, 0x08048000 );
buf, sz_fold, ft );
}
void PackLinuxI386sh::patchLoader()
{
}
void PackLinuxI386sh::patchLoader() { }
bool PackLinuxI386sh::getShellName(char *buf)
@ -104,7 +102,6 @@ bool PackLinuxI386sh::getShellName(char *buf)
};
for (int j=0; 0 != shname[j]; ++j) {
if (0==strcmp(shname[j], basename)) {
o_shname += 3; // space for "-c\x00"
return super::canPack();
}
}
@ -134,34 +131,12 @@ bool PackLinuxI386sh::canPack()
}
void PackLinuxI386sh::pack(OutputFile *fo)
void
PackLinuxI386sh::pack1(OutputFile *fo, Filter &)
{
#define PAGE_MASK (~0<<12)
opt->unix.blocksize = blocksize = file_size;
PackUnix::pack(fo);
// update loader
Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)const_cast<upx_byte *>(getLoader());
Elf_LE32_Phdr *const phdro = (Elf_LE32_Phdr *)(1+ehdr);
off_t const totlen = fo->getBytesWritten();
phdro[0].p_filesz = totlen;
phdro[0].p_memsz = PAGE_MASK & (~PAGE_MASK + totlen);
// Try to make brk() work by faking it for exec().
unsigned const brka = 0x08048000;
phdro[1].p_offset = 0xfff&brka;
phdro[1].p_vaddr = brka;
phdro[1].p_paddr = brka;
phdro[1].p_filesz = 0;
phdro[1].p_memsz = 0;
patchLoaderChecksum();
fo->seek(0, SEEK_SET);
fo->rewrite(ehdr, sizeof(cprElfhdr));
#undef PAGE_MASK
generateElfHdr(fo, linux_i386sh_fold, 0, 0, 0x08048000);
}
/*
vi:ts=4:et
*/

View File

@ -47,7 +47,7 @@ public:
virtual const int *getFilters() const { return NULL; }
virtual int buildLoader(const Filter *);
virtual void pack(OutputFile *fo);
virtual void pack1(OutputFile *fo, Filter &ft);
virtual bool canPack();
// virtual void unpack(OutputFile *fo) { super::unpack(fo); }

View File

@ -114,29 +114,24 @@ bool PackUnix::checkCompressionRatio(unsigned, unsigned) const
return true;
}
void PackUnix::pack(OutputFile *fo)
void PackUnix::pack1(OutputFile */*fo*/, Filter &/*ft*/)
{
// set options
blocksize = opt->unix.blocksize;
if (blocksize <= 0)
blocksize = BLOCKSIZE;
if ((off_t)blocksize > file_size)
blocksize = file_size;
// create a pseudo-unique program id for our paranoid stub
progid = getRandomId();
// init compression buffers
ibuf.alloc(blocksize);
obuf.allocForCompression(blocksize);
{
p_info hbuf;
set_native32(&hbuf.p_progid, progid);
set_native32(&hbuf.p_filesize, file_size);
set_native32(&hbuf.p_blocksize, blocksize);
obuf.write(&hbuf, sizeof(hbuf));
// derived class usually provides this
}
int
PackUnix::getStrategy(Filter &/*ft*/)
{
// Called just before reading and compressing each block.
// Might want to adjust blocksize, etc.
// If user specified the filter, then use it (-2==strategy).
// Else try the first two filters, and pick the better (2==strategy).
return ((opt->filter > 0) ? -2 : 2);
}
void PackUnix::pack2(OutputFile *fo, Filter &ft)
{
// compress blocks
unsigned total_in = 0;
unsigned total_out = 0;
@ -144,93 +139,128 @@ void PackUnix::pack(OutputFile *fo)
if (ui_total_passes == 1)
ui_total_passes = 0;
Filter ft(ph.level);
ft.addvalue = 0;
fi->seek(0, SEEK_SET);
for (;;)
{
for (;;) {
int const strategy = getStrategy(ft); // might adjust blocksize, etc.
int l = fi->read(ibuf, blocksize);
if (l == 0)
if (l == 0) {
break;
}
// Note: compression for a block can fail if the
// file is e.g. blocksize + 1 bytes long
// compress
ph.c_len = ph.u_len = l;
ph.overlap_overhead = 0;
ph.c_len = ph.u_len = l;
ft.buf_len = l;
// leave room for block sizes
unsigned char size[8];
set_native32(size+0, ph.u_len);
set_native32(size+4, ph.c_len); // will be rewritten
obuf.write(size, 8);
// compressWithFilters() updates u_adler _inside_ compress();
// that is, AFTER filtering. We want BEFORE filtering,
// so that decompression checks the end-to-end checksum.
unsigned const end_u_adler = upx_adler32(ph.u_adler, ibuf, ph.u_len);
compressWithFilters(&ft, OVERHEAD, strategy);
// If user specified the filter, then use it (-2==strategy).
// Else try the first two filters, and pick the better (2==strategy).
compressWithFilters(&ft, OVERHEAD, ((opt->filter > 0) ? -2 : 2));
if (ph.c_len < ph.u_len)
{
if (ph.c_len < ph.u_len) {
ph.overlap_overhead = OVERHEAD;
if (!testOverlappingDecompression(obuf, ph.overlap_overhead))
throwNotCompressible();
}
else
{
else {
// block is not compressible
ph.c_len = ph.u_len;
// must manually update checksum of compressed data
ph.c_adler = upx_adler32(ph.c_adler, ibuf, ph.u_len);
}
// update compressed size
set_native32(obuf - 4, ph.c_len);
// write block header
b_info blk_info; memset(&blk_info, 0, sizeof(blk_info));
set_native32(&blk_info.sz_unc, ph.u_len);
set_native32(&blk_info.sz_cpr, ph.c_len);
blk_info.b_method = ph.method;
blk_info.b_ftid = ph.filter;
blk_info.b_cto8 = ph.filter_cto;
fo->write(&blk_info, sizeof(blk_info));
ph.b_len += sizeof(b_info);
// write compressed data
if (ph.c_len < ph.u_len)
{
obuf.write(obuf, ph.c_len);
// FIXME: obuf is not discardable!
// verifyOverlappingDecompression();
if (ph.c_len < ph.u_len) {
fo->write(obuf, ph.c_len);
verifyOverlappingDecompression(); // uses ph.u_adler
}
else
obuf.write(ibuf, ph.u_len);
else {
fo->write(ibuf, ph.u_len);
}
ph.u_adler = end_u_adler;
total_in += ph.u_len;
total_out += ph.c_len;
}
if ((off_t)total_in != file_size)
throwEOFException();
// write block end marker (uncompressed size 0)
set_native32(obuf, 0);
obuf.write(obuf, 4);
// update header with totals
ph.u_len = total_in;
ph.c_len = total_out;
if ((off_t)total_in != file_size) {
throwEOFException();
}
}
void PackUnix::pack3(OutputFile *fo, Filter &ft)
{
upx_byte const *p = getLoader();
lsize = getLoaderSize();
patchFilter32(const_cast<upx_byte *>(p), lsize, &ft);
updateLoader(fo);
patchLoaderChecksum();
fo->write(p, lsize);
}
unsigned pos = obuf.seek(0, SEEK_CUR);
fo->write(obuf - pos, pos);
// write packheader
void PackUnix::pack4(OutputFile *fo, Filter &)
{
writePackHeader(fo);
// write overlay offset (needed for decompression)
set_native32(obuf, lsize);
fo->write(obuf, 4);
unsigned tmp;
set_native32(&tmp, overlay_offset);
fo->write(&tmp, sizeof(tmp));
}
updateLoader(fo);
fo->seek(0, SEEK_SET);
fo->rewrite(p, lsize);
void PackUnix::pack(OutputFile *fo)
{
Filter ft(ph.level);
ft.addvalue = 0;
ph.b_len = 0;
progid = 0;
// set options
blocksize = opt->unix.blocksize;
if (blocksize <= 0)
blocksize = BLOCKSIZE;
if ((off_t)blocksize > file_size)
blocksize = file_size;
// init compression buffers
ibuf.alloc(blocksize);
obuf.allocForCompression(blocksize);
fi->seek(0, SEEK_SET);
pack1(fo, ft); // generate Elf header, etc.
p_info hbuf;
set_native32(&hbuf.p_progid, progid);
set_native32(&hbuf.p_filesize, file_size);
set_native32(&hbuf.p_blocksize, blocksize);
fo->write(&hbuf, sizeof(hbuf));
pack2(fo, ft); // append the compressed body
// write block end marker (uncompressed size 0)
b_info hdr; memset(&hdr, 0, sizeof(hdr));
set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32);
fo->write(&hdr, sizeof(hdr));
pack3(fo, ft); // append loader
pack4(fo, ft); // append PackHeader and overlay_offset; update Elf header
// finally check the compression ratio
if (!checkFinalCompressionRatio(fo))
@ -305,42 +335,48 @@ void PackUnix::unpack(OutputFile *fo)
{
#define buf ibuf
int i;
int size[2];
b_info bhdr;
unsigned sz_unc, sz_cpr;
fi->readx(buf, 8);
ph.u_len = size[0] = get_native32(buf+0);
ph.c_len = size[1] = get_native32(buf+4);
fi->readx(&bhdr, sizeof(bhdr));
ph.u_len = sz_unc = get_native32(&bhdr.sz_unc);
ph.c_len = sz_cpr = get_native32(&bhdr.sz_cpr);
if (size[0] == 0) // uncompressed size 0 -> EOF
if (sz_unc == 0) // uncompressed size 0 -> EOF
{
// note: must reload size[1] as magic is always stored le32
size[1] = get_le32(buf+4);
if (size[1] != UPX_MAGIC_LE32) // size[1] must be h->magic
// note: must reload sz_cpr as magic is always stored le32
sz_cpr = get_le32(&bhdr.sz_cpr);
if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic
throwCompressedDataViolation();
break;
}
if (size[0] <= 0 || size[1] <= 0)
if (sz_unc <= 0 || sz_cpr <= 0)
throwCompressedDataViolation();
if (size[1] > size[0] || size[0] > (int)blocksize)
if (sz_cpr > sz_unc || sz_unc > blocksize)
throwCompressedDataViolation();
i = blocksize + OVERHEAD - size[1];
fi->readx(buf+i, size[1]);
i = blocksize + OVERHEAD - sz_cpr;
fi->readx(buf+i, sz_cpr);
// update checksum of compressed data
c_adler = upx_adler32(c_adler, buf + i, size[1]);
c_adler = upx_adler32(c_adler, buf + i, sz_cpr);
// decompress
if (size[1] < size[0])
{
if (sz_cpr < sz_unc) {
decompress(buf+i, buf, false);
if (0!=bhdr.b_ftid) {
Filter ft(ph.level);
ft.init(bhdr.b_ftid);
ft.cto = bhdr.b_cto8;
ft.unfilter(buf, sz_unc);
}
i = 0;
}
// update checksum of uncompressed data
u_adler = upx_adler32(u_adler, buf + i, size[0]);
total_in += size[1];
total_out += size[0];
u_adler = upx_adler32(u_adler, buf + i, sz_unc);
total_in += sz_cpr;
total_out += sz_unc;
// write block
if (fo)
fo->write(buf + i, size[0]);
fo->write(buf + i, sz_unc);
#undef buf
}

View File

@ -43,6 +43,7 @@ protected:
public:
virtual int getVersion() const { return 11; }
virtual const int *getFilters() const { return NULL; }
virtual int getStrategy(Filter &);
virtual void pack(OutputFile *fo);
virtual void unpack(OutputFile *fo);
@ -52,6 +53,11 @@ public:
protected:
// called by the generic pack()
virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data
virtual void pack3(OutputFile *, Filter &); // append loader
virtual void pack4(OutputFile *, Filter &); // append PackHeader
virtual void patchLoader() = 0;
virtual void patchLoaderChecksum() {}
virtual void updateLoader(OutputFile *) = 0;
@ -72,7 +78,19 @@ protected:
MemBuffer loader;
int lsize;
MemBuffer pt_dynamic;
int sz_dynamic;
// must agree with stub/linux.hh
struct b_info { // 12-byte header before each compressed block
unsigned sz_unc; // uncompressed_size
unsigned sz_cpr; // compressed_size
// FIXME: Unfortunately, endian-ness can BSWAP these four:
unsigned char b_method; // compression algorithm
unsigned char b_ftid; // filter id
unsigned char b_cto8; // filter parameter
unsigned char b_unused;
};
struct l_info { // 12-byte trailer in header for loader
unsigned l_checksum;
unsigned l_magic;

View File

@ -923,17 +923,8 @@ unsigned Packer::unoptimizeReloc32(upx_byte **in, upx_byte *image,
// loader util
**************************************************************************/
void Packer::initLoader(const void *pdata, int plen, int pinfo)
char const *Packer::identstr(unsigned &size)
{
if (pinfo < 0)
pinfo = ~3 & (3 + get_le16(pdata, plen - 2));
delete linker;
if (getFormat() < 128)
linker = new Linker(pdata, plen, pinfo); // little endian
else
linker = new BeLinker(pdata, plen, pinfo); // big endian
static const char identbig[] =
"\n\0"
"$Info: This file is packed with the UPX executable packer http://upx.tsx.org $"
@ -946,10 +937,30 @@ void Packer::initLoader(const void *pdata, int plen, int pinfo)
"$Id: UPX (C) 1996-2001 the UPX Team. All Rights Reserved. http://upx.tsx.org $"
"\n";
if (opt->small)
linker->addSection("IDENTSTR",identsmall,sizeof(identsmall));
if (opt->small) {
size = sizeof(identsmall);
return identsmall;
}
else {
size = sizeof(identbig);
return identbig;
}
}
void Packer::initLoader(const void *pdata, int plen, int pinfo)
{
if (pinfo < 0)
pinfo = ~3 & (3 + get_le16(pdata, plen - 2));
delete linker;
if (getFormat() < 128)
linker = new Linker(pdata, plen, pinfo); // little endian
else
linker->addSection("IDENTSTR",identbig,sizeof(identbig));
linker = new BeLinker(pdata, plen, pinfo); // big endian
unsigned size;
char const *const ident = identstr(size);
linker->addSection("IDENTSTR",ident,size);
}
@ -1453,9 +1464,6 @@ void Packer::compressWithFilters(Filter *parm_ft,
// filter
optimizeFilter(&ft, ibuf + filter_off, filter_len);
unsigned char *const save = new unsigned char[filter_len];
memcpy(save, ibuf + filter_off, filter_len);
bool success = ft.filter(ibuf + filter_off, filter_len);
if (ft.id != 0 && ft.calls == 0)
{
@ -1529,11 +1537,6 @@ void Packer::compressWithFilters(Filter *parm_ft,
}
// restore ibuf[] - unfilter with verify
ft.unfilter(ibuf + filter_off, filter_len, true);
for (unsigned k = 0; k < filter_len; ++k) {
if ((ibuf + filter_off)[k] != save[k]) {
printf("mismatch at %d\n", k);
}
}
//
if (strategy < 0)
break;

View File

@ -68,6 +68,7 @@ public:
int level; // compresison level 1..10
unsigned u_len;
unsigned c_len;
unsigned b_len; // total length of b_info blocks
unsigned u_adler;
unsigned c_adler;
off_t u_file_size;
@ -212,6 +213,7 @@ protected:
virtual int getLoaderSectionStart(const char *name, int *slen=NULL) const;
virtual void addFilter32(int filter_id);
virtual const char *getDecompressor() const;
char const *identstr(unsigned &size);
// stub and overlay util
static void handleStub(InputFile *fi, OutputFile *fo, long size);
@ -252,7 +254,7 @@ protected:
// compression buffers
MemBuffer ibuf; // input
MemBufferIO obuf; // output
MemBuffer obuf; // output
// UI handler
UiPacker *uip;

View File

@ -26,7 +26,10 @@
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
%define a_val 4
%define __NR_munmap 91
@ -34,7 +37,7 @@
;; control just falls through, after this part and compiled C code
;; are uncompressed.
fold_begin:
fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program
; patchLoader will modify to be
; dword sz_uncompressed, sz_compressed
; byte compressed_data...
@ -45,6 +48,7 @@ fold_begin:
; Move argc,argv,envp down so that we can insert more Elf_auxv entries.
; ld-linux.so.2 depends on AT_PHDR and AT_ENTRY, for instance
%define PAGE_SIZE ( 1<<12)
%define OVERHEAD 2048
%define MAX_ELF_HDR 512
@ -53,18 +57,19 @@ fold_begin:
mov edi, esp
call do_auxv
mov eax, [p_memsz + 2*szElf32_Phdr + szElf32_Ehdr + ebx] ; size of PT_DYNAMIC
sub esp, dword MAX_ELF_HDR + OVERHEAD
mov ecx, [e_entry + ebx] ; beyond compressed data
push esp ; argument: temp space
lea eax, [szElf32_Ehdr + 3*szElf32_Phdr + szl_info + szp_info + ebx + eax] ; 1st &b_info
push edi ; argument: AT_next
sub ecx, eax ; length of compressed data
push ebp ; argument: &decompress
push edx ; argument: my_elfhdr
add edx, [p_memsz + szElf32_Ehdr + edx]
push edx ; argument: uncbuf
push ecx ; argument: sz_compressed
push eax ; argument: 1st &b_info
EXTERN upx_main
call upx_main ; entry = upx_main(uncbuf, my_elfhdr, &decompress, AT_next, tmp_ehdr)
pop esi ; decompression buffer == (p_vaddr + p_memsz) of stub
pop ebx ; my_elfhdr
add esp, dword 3*4 + MAX_ELF_HDR + OVERHEAD ; remove 3 params, temp space
call upx_main ; entry = upx_main(b1st_info, sz_cpr, &decompress, AT_next, tmp_ehdr)
add esp, dword 5*4 + MAX_ELF_HDR + OVERHEAD ; remove 5 params, temp space
push eax ; save entry address
mov edi, [a_val + edi] ; AT_PHDR
@ -90,9 +95,10 @@ EXTERN make_hatch
xor eax,eax
rep stosd
mov ecx,esi ; my p_vaddr + p_memsz
mov bh,0 ; round down to 64KB boundary
sub ecx,ebx ; length to unmap
xor ecx, ecx ; 0
mov ch, PAGE_SIZE>>8 ; 0x1000
add ecx, [p_memsz + szElf32_Ehdr + ebx] ; length to unmap
mov bh, 0 ; from 0x401000 to 0x400000
push byte __NR_munmap
pop eax
jmp edx ; unmap ourselves via escape hatch, then goto entry

View File

@ -27,18 +27,26 @@
;; control just falls through, after this part and compiled C code
;; are uncompressed.
fold_begin: ;; this label is known to the Makefile
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_vaddr 2*4
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
fold_begin: ; enter: %ebx= &Elf32_Ehdr of this program
pop eax ; discard &dstlen
pop eax ; discard dstlen
pop eax ; Pop the argument count
mov ecx, esp ; argv starts just at the current stack top
lea edx, [ecx+eax*4+4] ; envp = &argv[argc + 1]
push eax ; Restore the stack
push ebp ; argument: &decompress
push ebx ; argument: &my_elfhdr
push edx ; argument: envp
push ecx ; argument: argv
lea edx, [esp+eax*4+4] ; envp = &argv[argc + 1]
mov esi, [e_entry + ebx]
add ebx, szElf32_Ehdr + szElf32_Phdr + szl_info
sub esi, ebx ; length
lea edi, [2 + ebp] ; f_unfilter, maybe
pusha ; (f_unf, cprLen, f_decpr, xx, cprSrc, envp, argv, argc)
EXTERN upx_main
call upx_main ; Call the UPX main function
hlt ; Crash if somehow upx_main does return

View File

@ -30,11 +30,15 @@
BITS 32
SECTION .text
fold_begin:
; patchLoader will modify to be
; dword sz_uncompressed, sz_compressed
; byte compressed_data...
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
fold_begin: ; enter: %ebx= uncDst
; also edx= szElf32_Ehdr + 2*szElf32_Phdr + &Elf32_Ehdr
pop eax ; discard &sz_uncompressed
pop eax ; discard sz_uncompressed
@ -48,39 +52,40 @@ fold_begin:
mov esi, esp
sub esp, byte 6*8 ; AT_PHENT, AT_PHNUM, AT_PAGESZ, AT_ENTRY, AT_PHDR, AT_NULL
mov edi, esp
call do_auxv
call do_auxv ; edi= &AT_NEXT
sub esp, dword MAX_ELF_HDR + OVERHEAD
push esp ; argument: temp space
push edi ; argument: AT_next
push ebp ; argument: &decompress
push edx ; argument: my_elfhdr
add ecx, PAGE_SIZE ; uncompressed stub fits in this
push ecx ; argument: uncbuf
xchg eax, ebx ; eax= uncDst
lea edx, [szl_info + szp_info + edx] ; cprSrc
mov ecx, [ edx] ; sz_unc
mov ebx, [4+ edx] ; sz_cpr
mov esi, eax ; extra copy of uncDst
pusha ; (&AT_NEXT,uncDst,f_decpr,&ehdr,{sz_cpr,cprSrc},{sz_unc,uncDst})
EXTERN upx_main
call upx_main ; entry = upx_main(uncbuf, my_elfhdr, &decompress, AT_next, tmp_ehdr)
pop esi ; decompression buffer
pop ebx ; my_elfhdr
add esp, dword 3*4 + MAX_ELF_HDR + OVERHEAD ; remove 3 params, temp space
call upx_main ; entry = upx_main(...)
pop ecx ; junk
push eax ; save entry address
popa ; edi= entry address; esi= uncDst
add esp, dword MAX_ELF_HDR + OVERHEAD ; remove temp space
pop ecx ; argc
pop edx ; $0 filename, to become argv[0]
push edx ; restore $0 filename
add esi, byte 3
inc ecx
push esi ; &uncompressed shell script
sub esi, byte 3
mov [esi], word 0x632d ; "-c"
inc ecx
push esi ; "-c"
push esi ; &"-c"
inc ecx
push edx ; argv[0] is duplicate of $0
push ecx ; new argc
push eax ; save entry address
push edi ; save entry address
; _dl_start and company (ld-linux.so.2) assumes that it has virgin stack,
; and does not initialize all its stack local variables to zero.

View File

@ -120,18 +120,12 @@ unpackExtent(
)
{
while (xo->size) {
unsigned cto8;
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
struct b_info h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
// Read and check block sizes.
xread(xi, (char *)&h, sizeof(h));
cto8 = h.sz_cpr;
h.sz_cpr >>= 8;
if (h.sz_unc == 0) { // uncompressed size 0 -> EOF
if (h.sz_cpr != UPX_MAGIC_LE32) // h.sz_cpr must be h->magic
err_exit(2);
@ -144,7 +138,7 @@ unpackExtent(
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
|| h.sz_unc > xo->size ) {
err_exit(5);
}
// Now we have:
@ -162,7 +156,7 @@ ERR_LAB
&& ((512 < out_len) // this block is longer than Ehdr+Phdrs
|| (xo->size==(unsigned)h.sz_unc) ) // block is last in Extent
) {
(*f_unf)(xo->buf, out_len, cto8);
(*f_unf)(xo->buf, out_len, h.b_cto8);
}
xi->buf += h.sz_cpr;
xi->size -= h.sz_cpr;
@ -322,46 +316,43 @@ ERR_LAB
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
char /*const*/ *const b1st_info,
unsigned const sz_compressed,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
) __asm__("upx_main");
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
char /*const*/ *const b1st_info,
unsigned const sz_compressed,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR+OVERHEAD]
)
{
struct cprElfhdr {
Elf32_Ehdr ehdr;
Elf32_Phdr phdr[2];
struct l_info linfo;
};
size_t const lsize = ((struct cprElfhdr const *)my_ehdr)->linfo.l_lsize;
Elf32_Phdr const *phdr = (Elf32_Phdr const *)(1+ehdr);
Elf32_Addr entry;
struct Extent xo;
struct Extent xi = { 0, sizeof(struct p_info) + lsize + CONST_CAST(char *, my_ehdr) };
struct Extent xi = { 0, b1st_info }; // location of 1st b_info
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0]; // sizeof(Ehdr+Phdrs), uncompressed
size_t const sz_pckhdrs = ((size_t *)xi.buf)[1]>>8; // sizeof(Ehdr+Phdrs), compressed
// sizeof(Ehdr+Phdrs), uncompressed
size_t const sz_elfhdrs = ((size_t *)xi.buf)[0];
// sizeof(Ehdr+Phdrs), compressed; including b_info header
size_t const sz_pckhdrs = sizeof(struct b_info) + ((size_t *)xi.buf)[1];
(void)uncbuf; // used by l_lx_sh.c
// Uncompress Ehdr and Phdrs.
xo.size = sz_elfhdrs; xo.buf = (char *)ehdr;
xi.size = 2*sizeof(size_t) + sz_pckhdrs;
xi.size = sz_pckhdrs;
unpackExtent(&xi, &xo, f_decompress, 0);
// Prepare to decompress the Elf headers again, into the first PT_LOAD.
xi.buf -= 2*sizeof(size_t) + sz_pckhdrs;
xi.size = ((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize;
xi.buf -= sz_pckhdrs;
xi.size = sz_compressed;
// av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present
// av[0].a_un.a_val is set again by do_xmap if PT_PHDR is present.
// Caller of upx_main assumes that AT_PHDR will be set into av[0] .
av[0].a_type = AT_PHDR; av[0].a_un.a_ptr = 1+(Elf32_Ehdr *)phdr->p_vaddr;
av[1].a_type = AT_PHENT; av[1].a_un.a_val = ehdr->e_phentsize;
av[2].a_type = AT_PHNUM; av[2].a_un.a_val = ehdr->e_phnum;

View File

@ -116,7 +116,6 @@ decompress:
;__LEXEC020__
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define MAP_FIXED 0x10
@ -126,7 +125,6 @@ decompress:
%define PROT_WRITE 2
%define PROT_EXEC 4
%define __NR_mmap 90
%define __NR_munmap 91
; Decompress the rest of this loader, and jump to it
unfold:
@ -135,10 +133,7 @@ unfold:
lodsd
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
mov eax, ebp ; &decompress
and eax, dword PAGE_MASK ; &my_elfhdr
mov edx, eax ; need my_elfhdr later
mov ah,0 ; round down to 64KB boundary
mov eax, 0x400000
push eax ; &destination
; mmap a page to hold the decompressed program
@ -148,16 +143,19 @@ unfold:
mov ch, PAGE_SIZE >> 8
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx
push ecx ; length
push eax ; destination
mov ebx, esp ; address of parameter vector for __NR_mmap
push byte __NR_mmap
pop eax
mov ebx, esp
int 0x80
xchg eax, ebx
mov bh, PAGE_SIZE>>8 ; ebx= 0x401000
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
lodsd ; junk cto8, algo, unused[2]
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &compressed_data

View File

@ -28,17 +28,23 @@
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
/*ENTRY(_start)*/
PHDRS
{
text PT_LOAD FILEHDR PHDRS ;
data PT_LOAD ; /* for setting brk(0) */
null PT_NULL; /* changed to PT_DYNAMIC for ldd */
}
SECTIONS
{
/* 0x00401000: l_lx_elf86.asm assumes 1 page up from 64KB boundary */
. = 0x00401000 + SIZEOF_HEADERS;
. = ALIGN(0x80);
. = 0x00401000 + SIZEOF_HEADERS + 12; /* 12==sizeof(l_info) */
.text : {
*(.text)
*(.data)
}
} : text
/* 0x08048000: customary Linux/x86 Elf .text start */
/* PackLinuxI386::buildLinuxLoader will overwrite the address anyway. */
. = 0x08048000 + (0xfff & .);
.data : {
}
} : data
}

View File

@ -139,7 +139,7 @@ do_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
static int
go_self(char const *tmpname, char *argv[], char *envp[])
{
// FIXME: why not use "/proc/self/fd/XX"? *BSD doesn't have it?
// Old FreeBSD does not have /proc/self, so use /proc/<pid> instead.
// Open the temp file.
int const fdi = open(tmpname, O_RDONLY, 0);
@ -181,6 +181,11 @@ go_self(char const *tmpname, char *argv[], char *envp[])
// UPX & NRV stuff
**************************************************************************/
typedef void f_unfilter(
nrv_byte *, // also addvalue
nrv_uint,
unsigned cto8 // junk in high 24 bits
);
typedef int f_expand(
const nrv_byte *src, nrv_uint src_len,
nrv_byte *dst, nrv_uint *dst_len );
@ -193,16 +198,24 @@ typedef int f_expand(
**************************************************************************/
void upx_main(
char *argv[],
f_unfilter *const f_unf,
unsigned cprLen,
f_expand *const f_decompress,
int junk2,
char /*const*/ *cprSrc,
char *envp[],
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress
char *argv[],
int argc
) __asm__("upx_main");
void upx_main(
char *argv[],
f_unfilter *const f_unf,
unsigned cprLen,
f_expand *const f_decompress,
int junk,
char /*const*/ *cprSrc,
char *envp[],
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress
char *argv[],
int argc
)
{
// file descriptor
@ -213,9 +226,7 @@ void upx_main(
char *tmpname;
Elf32_Phdr const *const phdr = (Elf32_Phdr const *)
(my_ehdr->e_phoff + (char const *)my_ehdr);
struct Extent xi = { phdr[1].p_memsz, (char *)phdr[1].p_vaddr };
struct Extent xi = { cprLen, cprSrc };
char *next_unmap = (char *)(PAGE_MASK & (unsigned)xi.buf);
struct p_info header;
@ -223,6 +234,8 @@ void upx_main(
// temporary file name
char tmpname_buf[20];
(void)junk;
//
// ----- Step 0: set /proc/self using /proc/<pid> -----
//
@ -347,18 +360,13 @@ void upx_main(
for (;;)
{
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
struct b_info h;
int i;
// Read and check block sizes.
{
register char *__d0, *__d1;
__asm__ __volatile__( "movsl; movsl"
__asm__ __volatile__( "movsl; movsl; movsl"
: "=&D" (__d0), "=&S" (__d1)
: "0" (&h), "1" (xi.buf)
: "memory");
@ -373,9 +381,10 @@ void upx_main(
goto error;
break;
}
if (h.sz_cpr <= 0)
goto error;
if (h.sz_cpr > h.sz_unc || h.sz_unc > (int32_t)header.p_blocksize)
// Note: if sz_unc == sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
if (h.sz_cpr > h.sz_unc || h.sz_cpr > header.p_blocksize)
goto error;
// Now we have:
// assert(h.sz_cpr <= h.sz_unc);
@ -387,6 +396,9 @@ void upx_main(
i = (*f_decompress)(xi.buf, h.sz_cpr, buf, &out_len);
if (i != 0 || out_len != (nrv_uint)h.sz_unc)
goto error;
// Right now, unfilter is combined with decompression.
// (*f_unfilter)(buf, out_len, cto8);
(void)f_unf;
}
else
{
@ -486,6 +498,7 @@ void upx_main(
waitpid(-1, (int *)0, 0);
// Execute the original program.
(void)argc;
execve(tmpname, argv, envp);

View File

@ -138,49 +138,53 @@ decompress:
;__LEXEC020__
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define MAP_FIXED 0x10
%define MAP_PRIVATE 0x02
%define MAP_ANONYMOUS 0x20
%define PROT_READ 1
%define PROT_WRITE 2
%define PROT_EXEC 4
%define __NR_mmap 90
; Decompress the rest of this loader, and jump to it
unfold:
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
mov ecx, PAGE_MASK
push esi ; &dst
mov ebx, ebp ; &decompress
and ebx, ecx ; &my_elfhdr
neg ecx ; ecx= PAGE_SIZE
cld
lodsd ; sz_uncompressed
lodsd ; sz_compressed
;; Compressed code now begins at fold_begin.
;; We want decompressed code to begin at fold_begin, too.
;; Move the compressed code to the high end of the page.
;; Assume non-overlapping so that forward movsb is OK.
lea edi, [ecx + ebx] ; high end of page
push eax ; srclen (of both movsb and decompress)
sub edi, eax ; dst of movsb
push edi ; &src for decompression (after movsb)
xchg ecx, eax ; ecx= len of movsb
rep movsb
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &src
pop eax ; discard srclen
pop eax ; &dst == fold_begin
;; icache lookahead of compressed code after "call unfold" is still there.
;; Synchronize with dcache of decompressed code.
pushf
push cs
push eax
iret ; back to fold_begin!
main:
pop ebp ; &decompress
lodsd
push eax ; sz_uncompressed (junk, actually)
push esp ; &sz_uncompressed
mov eax, 0x400000
push eax ; &destination
; mmap a page to hold the decompressed program
xor ecx, ecx
push ecx
push ecx
mov ch, PAGE_SIZE >> 8
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx ; length
push eax ; destination
mov ebx, esp ; address of parameter vector for __NR_mmap
push byte __NR_mmap
pop eax
int 0x80
xchg eax, ebx
mov bh, PAGE_SIZE>>8 ; ebx= 0x401000
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
lodsd ; junk cto8, algo, unused[2]
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop eax ; discard &compressed_data
pop eax ; discard sz_compressed
ret ; &destination
main:
pop ebp ; &decompress
call unfold
eof:
@ -190,3 +194,4 @@ eof:
dw eof
; vi:ts=8:et:nowrap

View File

@ -30,9 +30,8 @@ OUTPUT_ARCH(i386)
/*ENTRY(_start)*/
SECTIONS
{
/* 0x08048000: customary Linux/x86 Elf .text start */
. = 0x08048000 + SIZEOF_HEADERS;
. = ALIGN(0x80); /* room for Ehdr, 2*Phdr, l_info */
/* 0x00401000: l_lx_exec86.asm assumes 1 page up from 64KB boundary */
. = 0x00401000 + SIZEOF_HEADERS + 12; /* 12==sizeof(l_info) */
.data : { /* put everything together in one Phdr */
*(.text)
*(.rodata)

View File

@ -114,10 +114,7 @@ unpackExtent(
)
{
while (xo->size) {
struct {
int32_t sz_unc; // uncompressed
int32_t sz_cpr; // compressed
} h;
struct b_info h;
// Note: if h.sz_unc == h.sz_cpr then the block was not
// compressible and is stored in its uncompressed form.
@ -135,7 +132,7 @@ unpackExtent(
ERR_LAB
}
if (h.sz_cpr > h.sz_unc
|| h.sz_unc > (int32_t)xo->size ) {
|| h.sz_unc > xo->size ) {
err_exit(5);
}
// Now we have:
@ -272,48 +269,34 @@ ERR_LAB
**************************************************************************/
void *upx_main(
char *const uncbuf,
Elf32_Ehdr const *const my_ehdr,
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr
unsigned const junk,
f_expand *const f_decompress,
Elf32_Ehdr *const ehdr, // temp char[MAX_ELF_HDR]
struct Extent xi,
struct Extent xo
) __asm__("upx_main");
void *upx_main(
char *const uncbuf, // place to put decompressed shell script
Elf32_Ehdr const *const my_ehdr, // to get compressed size and data
f_expand *const f_decompress,
Elf32_auxv_t *const av,
Elf32_Ehdr *const ehdr // temp char[MAX_ELF_HDR]
unsigned const junk,
f_expand *const f_decompress,
Elf32_Ehdr *const ehdr, // temp char[MAX_ELF_HDR]
struct Extent xi,
struct Extent xo
)
{
// 'fn' and 'efn' must not suffer constant-propagation by gcc
// UPX2 = offset to name_of_shell
// UPX3 = strlen(name_of_shell)
char * /*const*/ volatile fn = UPX2 + xo.buf; // past "-c" and "#!"
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
Elf32_Addr entry;
size_t const lsize = sizeof(struct p_info) +
*(unsigned short const *)(0x7c + (char const *)my_ehdr);
struct Extent xi = { // describe compressed shell script
((Elf32_Phdr const *)(1 + my_ehdr))->p_filesz - lsize,
lsize + CONST_CAST(char *, my_ehdr)
};
struct Extent xo = { ((struct p_info *)xi.buf)[-1].p_filesize, uncbuf };
// Allocate space for decompressed shell script.
// "1+": guarantee '\0' terminator at end of decompressed script
if (xo.buf != do_mmap(xo.buf, 1+3+xo.size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)) {
err_exit(20);
ERR_LAB
}
// Uncompress shell script
xo.buf += 3; // leave room for "-c" argument
(void)junk;
unpackExtent(&xi, &xo, f_decompress);
{ // Map shell program
// 'fn' and 'efn' must not suffer constant-propagation by gcc
// UPX2 = 3 + offset to name_of_shell
// UPX3 = strlen(name_of_shell)
char * /*const*/ volatile fn = UPX2 + uncbuf; // past "-c" and "#!"
char * /*const*/ volatile efn = UPX3 + fn; // &terminator
char const c = *efn; *efn = 0; // terminator
entry = getexec(fn, ehdr, av);
*efn = c; // replace terminator character

View File

@ -106,12 +106,8 @@ decompress:
;__LEXEC020__
%define PAGE_MASK (~0<<12)
%define PAGE_SIZE ( 1<<12)
%define szElf32_Ehdr 0x34
%define p_memsz 5*4
%define MAP_FIXED 0x10
%define MAP_PRIVATE 0x02
%define MAP_ANONYMOUS 0x20
@ -120,42 +116,52 @@ decompress:
%define PROT_EXEC 4
%define __NR_mmap 90
%define szElf32_Ehdr 0x34
%define szElf32_Phdr 8*4
%define e_entry (16 + 2*2 + 4)
%define p_memsz 5*4
%define szl_info 12
%define szp_info 12
%define p_filesize 4
; Decompress the rest of this loader, and jump to it
unfold:
pop esi ; &{ sz_uncompressed, sz_compressed, compressed_data...}
cld
lodsd
push eax ; sz_uncompressed (junk, actually)
push eax ; sz_uncompressed of folded stub (junk, actually)
push esp ; &sz_uncompressed
mov eax, ebp ; &decompress
and eax, dword PAGE_MASK ; &my_elfhdr
mov edx, eax ; need my_elfhdr later
add eax, [p_memsz + szElf32_Ehdr + eax]
mov edx, 0x00800000 ; origin of this program
mov eax, [p_memsz + szElf32_Ehdr + edx] ; length of loaded pages
add eax, edx
add edx, szElf32_Ehdr + 2*szElf32_Phdr ; convenient ptr
push eax ; &destination
; mmap a page to hold the decompressed program
xor ecx,ecx
push ecx
push ecx
mov ch, PAGE_SIZE >> 8
; mmap space for unfolded stub, and uncompressed script
mov ecx, [szl_info + p_filesize + edx] ; script size
add ecx, 1+ 3+ (3 -1)+ PAGE_SIZE ; '\0' + "-c" + decompr_overrun + stub
push eax ; offset (ignored when MAP_ANONYMOUS)
push eax ; fd (ignored when MAP_ANONYMOUS)
push byte MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS
push byte PROT_READ | PROT_WRITE | PROT_EXEC
push ecx
push ecx ; length
push eax ; destination
mov ebx, esp ; address of parameter vector for __NR_mmap
push byte __NR_mmap
pop eax
mov ebx, esp
int 0x80
lea ebx, [3+ PAGE_SIZE + eax] ; place for uncompressed script
add esp, byte 6*4 ; discard args to mmap
lodsd
push eax ; sz_compressed
push eax ; sz_compressed of folded stub
lodsd ; junk cto8, algo, unused[2]
push esi ; &compressed_data
call ebp ; decompress(&src, srclen, &dst, &dstlen)
pop ecx ; discard &compressed_data
pop ecx ; discard sz_compressed
pop ecx ; &destination
jmp ecx ; goto fold_begin at p_vaddr + p_memsz
pop eax ; discard &compressed_data
pop eax ; discard sz_compressed
ret ; &destination
main:
pop ebp ; &decompress
call unfold

View File

@ -46,10 +46,4 @@ SECTIONS
*(.bss)
*(COMMON)
}
/* 0x08048000: customary Linux/x86 Elf .text start */
/*
. = 0x08048000 + (0xfff & .);
.data : {
}
*/
}

View File

@ -88,6 +88,15 @@ typedef unsigned int nrv_uint32;
// From ../p_unix.h
struct b_info { // 12-byte header before each compressed block
unsigned sz_unc; // uncompressed_size
unsigned sz_cpr; // compressed_size
unsigned char b_method; // compression algorithm
unsigned char b_ftid; // filter id
unsigned char b_cto8; // filter parameter
unsigned char b_unused;
};
struct l_info // 12-byte trailer in header for loader (offset 116)
{
uint32_t l_checksum;