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:
parent
9005e50049
commit
40fddf1715
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
42
src/mem.cpp
42
src/mem.cpp
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
18
src/p_elf.h
18
src/p_elf.h
|
@ -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 */
|
||||
|
||||
|
||||
|
|
188
src/p_lx_elf.cpp
188
src/p_lx_elf.cpp
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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[]
|
||||
|
||||
};
|
||||
|
||||
|
|
345
src/p_lx_exc.cpp
345
src/p_lx_exc.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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); }
|
||||
|
|
206
src/p_unix.cpp
206
src/p_unix.cpp
|
@ -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
|
||||
}
|
||||
|
||||
|
|
18
src/p_unix.h
18
src/p_unix.h
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -46,10 +46,4 @@ SECTIONS
|
|||
*(.bss)
|
||||
*(COMMON)
|
||||
}
|
||||
/* 0x08048000: customary Linux/x86 Elf .text start */
|
||||
/*
|
||||
. = 0x08048000 + (0xfff & .);
|
||||
.data : {
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user