Start re-organizing the packing of Elf, by making Elf32 come first,

with Big endian and Little endian derived from it.
I386 still uses the old way, but PowerPC (both Linux and Darwin [Mac])
use the new way.
	p_elf.h p_lx_elf.cpp p_lx_elf.h p_lx_exc.cpp p_lx_exc.h
	p_unix.cpp p_unix.h p_vmlinx.cpp p_vmlinx.h p_vmlinz.cpp

committer: jreiser <jreiser> 1108940224 +0000
This commit is contained in:
John Reiser 2005-02-20 22:57:04 +00:00
parent e2763b4826
commit 664a82e7c9
9 changed files with 1249 additions and 346 deletions

View File

@ -80,6 +80,7 @@ struct Elf_LE32_Phdr
enum {
PT_LOAD = 1, /* Loadable program segment */
PT_DYNAMIC = 2, /* Dynamic linking information */
PT_INTERP = 3, /* Name of program interpreter */
PT_PHDR = 6 /* Entry for header table itself */
};
@ -152,6 +153,146 @@ struct Elf_LE32_Dyn
}
__attribute_packed;
typedef unsigned int u32;
typedef unsigned short u16;
struct Elf32_Ehdr
{
unsigned char e_ident[16]; /* Magic number and other info */
u16 e_type; /* Object file type */
u16 e_machine; /* Architecture */
u32 e_version; /* Object file version */
u32 e_entry; /* Entry point virtual address */
u32 e_phoff; /* Program header table file offset */
u32 e_shoff; /* Section header table file offset */
u32 e_flags; /* Processor-specific flags */
u16 e_ehsize; /* ELF header size in bytes */
u16 e_phentsize; /* Program header table entry size */
u16 e_phnum; /* Program header table entry count */
u16 e_shentsize; /* Section header table entry size */
u16 e_shnum; /* Section header table entry count */
u16 e_shstrndx; /* Section header string table index */
enum { // e_ident
EI_CLASS = 4,
EI_DATA = 5,
EI_VERSION = 6,
EI_OSABI = 7
};
enum { // EI_CLASS
ELFCLASS32 = 1, /* 32-bit objects */
ELFCLASS64 = 2 /* 64-bit objects */
};
enum { // EI_DATA
ELFDATA2LSB = 1, /* 2's complement, little endian */
ELFDATA2MSB = 2 /* 2's complement, big endian */
};
enum { // e_type
ET_NONE = 0, /* No file type */
ET_REL = 1, /* Relocatable file */
ET_EXEC = 2, /* Executable file */
ET_DYN = 3, /* Shared object file */
ET_CORE = 4 /* Core file */
};
enum { // e_version
EV_CURRENT = 1
};
enum { // e_machine
EM_PPC = 20
};
}
__attribute_packed;
// Program segment header.
struct Elf32_Phdr
{
u32 p_type; /* Segment type */
u32 p_offset; /* Segment file offset */
u32 p_vaddr; /* Segment virtual address */
u32 p_paddr; /* Segment physical address */
u32 p_filesz; /* Segment size in file */
u32 p_memsz; /* Segment size in memory */
u32 p_flags; /* Segment flags */
u32 p_align; /* Segment alignment */
// Values for p_type
enum {
PT_LOAD = 1, /* Loadable program segment */
PT_DYNAMIC = 2, /* Dynamic linking information */
PT_INTERP = 3, /* Name of program interpreter */
PT_PHDR = 6 /* Entry for header table itself */
};
// Values for p_flags
enum { PF_X = (1 << 0) }; /* Segment is executable */
enum { PF_W = (1 << 1) }; /* Segment is writable */
enum { PF_R = (1 << 2) }; /* Segment is readable */
}
__attribute_packed;
struct Elf32_Shdr
{
u32 sh_name; /* Section name (string tbl index) */
u32 sh_type; /* Section type */
u32 sh_flags; /* Section flags */
u32 sh_addr; /* Section virtual addr at execution */
u32 sh_offset; /* Section file offset */
u32 sh_size; /* Section size in bytes */
u32 sh_link; /* Link to another section */
u32 sh_info; /* Additional section information */
u32 sh_addralign; /* Section alignment */
u32 sh_entsize; /* Entry size if section holds table */
enum { // values for sh_type
SHT_NULL = 0, /* Section header table entry unused */
SHT_PROGBITS = 1,/* Program data */
SHT_SYMTAB = 2, /* Symbol table */
SHT_STRTAB = 3, /* String table */
SHT_RELA = 4, /* Relocation entries with addends */
SHT_HASH = 5, /* Symbol hash table */
SHT_DYNAMIC = 6, /* Dynamic linking information */
SHT_NOTE = 7, /* Notes */
SHT_NOBITS = 8, /* Program space with no data (bss) */
SHT_REL = 9, /* Relocation entries, no addends */
SHT_SHLIB = 10, /* Reserved */
SHT_DYNSYM = 11, /* Dynamic linker symbol table */
/* 12, 13 hole */
SHT_INIT_ARRAY = 14, /* Array of constructors */
SHT_FINI_ARRAY = 15, /* Array of destructors */
SHT_PREINIT_ARRAY = 16, /* Array of pre-constructors */
SHT_GROUP = 17, /* Section group */
SHT_SYMTAB_SHNDX = 18, /* Extended section indeces */
SHT_NUM = 19 /* Number of defined types. */
};
enum { // values for sh_flags
SHF_WRITE = (1 << 0), /* Writable */
SHF_ALLOC = (1 << 1), /* Occupies memory during execution */
SHF_EXECINSTR = (1 << 2), /* Executable */
SHF_MERGE = (1 << 4), /* Might be merged */
SHF_STRINGS = (1 << 5), /* Contains nul-terminated strings */
SHF_INFO_LINK = (1 << 6), /* `sh_info' contains SHT index */
SHF_LINK_ORDER = (1 << 7), /* Preserve order after combining */
};
}
__attribute_packed;
struct Elf32_Dyn
{
u32 d_tag;
u32 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 */
};
}
__attribute_packed;
#endif /* already included */

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,120 @@
#define __UPX_P_LX_ELF_H
class PackLinuxElf32 : public PackUnix
{
typedef PackUnix super;
public:
PackLinuxElf32(InputFile *f);
virtual ~PackLinuxElf32();
/*virtual int buildLoader(const Filter *);*/
virtual bool canUnpackVersion(int version) const { return (version >= 11); }
protected:
virtual int checkEhdr(
Elf32_Ehdr const *ehdr,
unsigned char e_machine,
unsigned char ei_class,
unsigned char ei_data) const;
virtual const int *getCompressionMethods(int method, int level) const;
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 pack header
virtual off_t getbrk(const Elf32_Phdr *phdr, int e_phnum) const;
virtual void generateElfHdr(
OutputFile *,
void const *proto,
unsigned const brka
);
virtual int buildLinuxLoader(
upx_byte const *const proto, // assembly-only sections
unsigned const szproto,
upx_byte const *const fold, // linked assembly + C section
unsigned const szfold,
Filter const *ft
);
virtual void patchLoader();
virtual void updateLoader(OutputFile *fo);
virtual void unpack(OutputFile *fo);
protected:
Elf32_Ehdr ehdri; // from input file
Elf32_Phdr *phdri; // for input file
unsigned sz_phdrs; // sizeof Phdr[]
unsigned sz_elf_hdrs; // all Elf headers
struct cprElfHdr1 {
struct Elf32_Ehdr ehdr;
struct Elf32_Phdr phdr[1];
struct l_info linfo;
}
__attribute_packed;
struct cprElfHdr2 {
struct Elf32_Ehdr ehdr;
struct Elf32_Phdr phdr[2];
struct l_info linfo;
}
__attribute_packed;
struct cprElfHdr3 {
struct Elf32_Ehdr ehdr;
struct Elf32_Phdr phdr[3];
struct l_info linfo;
}
__attribute_packed;
struct cprElfHdr3 elfout;
};
class PackLinuxElf32Be : public PackLinuxElf32
{
typedef PackLinuxElf32 super;
protected:
PackLinuxElf32Be(InputFile *f) : super(f) { }
virtual unsigned get_native32(const void *b) const { return get_be32(b); }
virtual unsigned get_native16(const void *b) const { return get_be16(b); }
virtual void set_native32(void *b, unsigned v) const { set_be32(b, v); }
virtual void set_native16(void *b, unsigned v) const { set_be16(b, v); }
};
/*************************************************************************
// linux/elf32ppc
**************************************************************************/
class PackLinuxElf32ppc : public PackLinuxElf32Be
{
typedef PackLinuxElf32Be super;
public:
PackLinuxElf32ppc(InputFile *f);
virtual ~PackLinuxElf32ppc();
virtual int getFormat() const { return UPX_F_LINUX_ELF_PPC; }
virtual const char *getName() const { return "linux/ElfPPC"; }
virtual const int *getFilters() const;
virtual bool canPack();
protected:
virtual void pack3(OutputFile *, Filter &); // append loader
virtual const int *getCompressionMethods(int method, int level) const;
virtual int buildLinuxLoader(
upx_byte const *const proto, // assembly-only sections
unsigned const szproto,
upx_byte const *const fold, // linked assembly + C section
unsigned const szfold,
Filter const *ft
);
virtual int buildLoader(const Filter *);
virtual void generateElfHdr(
OutputFile *,
void const *proto,
unsigned const brka
);
};
/*************************************************************************
// linux/elf386
**************************************************************************/
@ -53,18 +167,6 @@ public:
virtual bool canUnpackVersion(int version) const
{ return (version >= 11); }
protected:
struct Extent {
off_t offset;
off_t size;
};
virtual void packExtent(const Extent &x,
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, unsigned szb_info );
protected:
virtual void pack1(OutputFile *, Filter &); // generate executable header
virtual void pack2(OutputFile *, Filter &); // append compressed data
@ -72,8 +174,8 @@ protected:
virtual void patchLoader();
Elf_LE32_Ehdr ehdri; // from input file
Elf_LE32_Phdr *phdri; // for input file
Elf32_Ehdr ehdri; // from input file
Elf32_Phdr *phdri; // for input file
unsigned sz_phdrs; // sizeof Phdr[]
};

View File

@ -37,12 +37,12 @@
#include "p_unix.h"
#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
#define PT_LOAD Elf32_Phdr::PT_LOAD
#define PT_DYNAMIC Elf32_Phdr::PT_DYNAMIC
#define DT_NULL Elf32_Dyn::DT_NULL
#define DT_NEEDED Elf32_Dyn::DT_NEEDED
#define DT_STRTAB Elf32_Dyn::DT_STRTAB
#define DT_STRSZ Elf32_Dyn::DT_STRSZ
/*************************************************************************
@ -88,12 +88,13 @@ PackLinuxI386::generateElfHdr(
{
cprElfHdr1 *const h1 = (cprElfHdr1 *)&elfout;
cprElfHdr2 *const h2 = (cprElfHdr2 *)&elfout;
memcpy(h2, proto, sizeof(*h2));
cprElfHdr3 *const h3 = (cprElfHdr3 *)&elfout;
memcpy(h3, proto, sizeof(*h3)); // reads beyond, but OK
assert(h2->ehdr.e_phoff == sizeof(Elf_LE32_Ehdr));
assert(h2->ehdr.e_phoff == sizeof(Elf32_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_ehsize == sizeof(Elf32_Ehdr));
assert(h2->ehdr.e_phentsize == sizeof(Elf32_Phdr));
assert(h2->ehdr.e_shnum == 0);
#if 0 //{
@ -129,6 +130,11 @@ PackLinuxI386::generateElfHdr(
memset(&h2->linfo, 0, sizeof(h2->linfo));
fo->write(h2, sizeof(*h2));
}
else if (ph.format==UPX_F_LINUX_ELFI_i386) {
assert(h3->ehdr.e_phnum==3);
memset(&h3->linfo, 0, sizeof(h3->linfo));
fo->write(h3, sizeof(*h3));
}
else {
assert(false); // unknown ph.format, PackUnix::generateElfHdr
}
@ -152,8 +158,6 @@ PackLinuxI386::pack4(OutputFile *fo, Filter &ft)
((elfout.ehdr.e_phnum==3) ? (unsigned) elfout.phdr[2].p_memsz : 0) ;
super::pack4(fo, ft); // write PackHeader and overlay_offset
unsigned eod = fo->getBytesWritten();
elfout.phdr[0].p_filesz = eod;
#if 0 // {
// /usr/bin/strip from RedHat 8.0 (binutils-2.13.90.0.2-2)
@ -170,10 +174,11 @@ PackLinuxI386::pack4(OutputFile *fo, Filter &ft)
// Supply a "linking view" that covers everything,
// so that 'strip' does not omit everything.
Elf_LE32_Shdr shdr;
Elf32_Shdr shdr;
// The section header string table.
char const shstrtab[] = "\0.\0.shstrtab";
unsigned eod = elfout.phdr[0].p_filesz;
set_native32(&elfout.ehdr.e_shoff, eod);
set_native16(&elfout.ehdr.e_shentsize, sizeof(shdr));
set_native16(&elfout.ehdr.e_shnum, 3);
@ -181,14 +186,14 @@ PackLinuxI386::pack4(OutputFile *fo, Filter &ft)
// An empty Elf32_Shdr for space as a null index.
memset(&shdr, 0, sizeof(shdr));
set_native32(&shdr.sh_type, Elf_LE32_Shdr::SHT_NULL);
set_native32(&shdr.sh_type, Elf32_Shdr::SHT_NULL);
fo->write(&shdr, sizeof(shdr));
// Cover all the bits we need at runtime.
memset(&shdr, 0, sizeof(shdr));
set_native32(&shdr.sh_name, 1);
set_native32(&shdr.sh_type, Elf_LE32_Shdr::SHT_PROGBITS);
set_native32(&shdr.sh_flags, Elf_LE32_Shdr::SHF_ALLOC);
set_native32(&shdr.sh_type, Elf32_Shdr::SHT_PROGBITS);
set_native32(&shdr.sh_flags, Elf32_Shdr::SHF_ALLOC);
set_native32(&shdr.sh_addr, elfout.phdr[0].p_vaddr);
set_native32(&shdr.sh_offset, overlay_offset);
set_native32(&shdr.sh_size, eod - overlay_offset);
@ -198,7 +203,7 @@ PackLinuxI386::pack4(OutputFile *fo, Filter &ft)
// A section header for the section header string table.
memset(&shdr, 0, sizeof(shdr));
set_native32(&shdr.sh_name, 3);
set_native32(&shdr.sh_type, Elf_LE32_Shdr::SHT_STRTAB);
set_native32(&shdr.sh_type, Elf32_Shdr::SHT_STRTAB);
set_native32(&shdr.sh_offset, 3*sizeof(shdr) + eod);
set_native32(&shdr.sh_size, sizeof(shstrtab));
fo->write(&shdr, sizeof(shdr));
@ -238,21 +243,28 @@ PackLinuxI386::buildLinuxLoader(
{
initLoader(proto, szproto);
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;
unsigned fold_hdrlen = 0;
if (0 < szfold) {
cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold;
fold_hdrlen = umax(0x80, sizeof(hf->ehdr) +
hf->ehdr.e_phentsize * hf->ehdr.e_phnum + sizeof(l_info) );
h.sz_unc = (szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen);
h.b_method = (unsigned char) ph.method;
h.b_ftid = (unsigned char) ph.filter;
h.b_cto8 = (unsigned char) ph.filter_cto;
}
unsigned char const *const uncLoader = fold_hdrlen + 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,
if (0 < szfold) {
unsigned sz_cpr;
int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &sz_cpr,
NULL, ph.method, 10, NULL, NULL );
h.sz_cpr = sz_cpr;
if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc)
throwInternalError("loader compression failed");
}
memcpy(cprLoader, &h, sizeof(h));
// This adds the definition to the "library", to be used later.
@ -396,7 +408,7 @@ int PackLinuxI386::getLoaderPrefixSize() const
**************************************************************************/
// basic check of an Linux ELF Ehdr
int PackLinuxI386::checkEhdr(const Elf_LE32_Ehdr *ehdr) const
int PackLinuxI386::checkEhdr(const Elf32_Ehdr *ehdr) const
{
const unsigned char * const buf = ehdr->e_ident;
@ -414,7 +426,7 @@ int PackLinuxI386::checkEhdr(const Elf_LE32_Ehdr *ehdr) const
return 4;
if (ehdr->e_phnum < 1)
return 5;
if (ehdr->e_phentsize != sizeof(Elf_LE32_Phdr))
if (ehdr->e_phentsize != sizeof(Elf32_Phdr))
return 6;
// check for Linux kernels
@ -435,7 +447,7 @@ int PackLinuxI386::checkEhdr(const Elf_LE32_Ehdr *ehdr) const
}
off_t PackLinuxI386::getbrk(const Elf_LE32_Phdr *phdr, int e_phnum) const
off_t PackLinuxI386::getbrk(const Elf32_Phdr *phdr, int e_phnum) const
{
off_t brka = 0;
for (int j = 0; j < e_phnum; ++phdr, ++j) {
@ -448,6 +460,21 @@ off_t PackLinuxI386::getbrk(const Elf_LE32_Phdr *phdr, int e_phnum) const
return brka;
}
off_t PackLinuxI386::getbase(const Elf32_Phdr *phdr, int e_phnum) const
{
off_t base = ~0u;
for (int j = 0; j < e_phnum; ++phdr, ++j) {
if (phdr->PT_LOAD == phdr->p_type) {
if ((unsigned)phdr->p_vaddr < base)
base = phdr->p_vaddr;
}
}
if (0!=base) {
return base;
}
return 0x12000;
}
/*************************************************************************
//
@ -458,7 +485,7 @@ bool PackLinuxI386::canPack()
if (exetype != 0)
return super::canPack();
Elf_LE32_Ehdr ehdr;
Elf32_Ehdr ehdr;
unsigned char *buf = ehdr.e_ident;
fi->readx(&ehdr, sizeof(ehdr));

View File

@ -74,8 +74,9 @@ protected:
virtual void updateLoader(OutputFile *);
// ELF util
virtual int checkEhdr(const Elf_LE32_Ehdr *ehdr) const;
virtual off_t getbrk(const Elf_LE32_Phdr *phdr, int e_phnum) const;
virtual int checkEhdr(const Elf32_Ehdr *ehdr) const;
virtual off_t getbrk(const Elf32_Phdr *phdr, int e_phnum) const;
virtual off_t getbase(const Elf32_Phdr *phdr, int e_phnum) const;
enum {
UPX_ELF_MAGIC = 0x5850557f // "\x7fUPX"
@ -84,22 +85,22 @@ protected:
unsigned n_mru;
struct cprElfHdr1 {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[1];
struct Elf32_Ehdr ehdr;
struct Elf32_Phdr phdr[1];
struct l_info linfo;
}
__attribute_packed;
struct cprElfHdr2 {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[2];
struct Elf32_Ehdr ehdr;
struct Elf32_Phdr phdr[2];
struct l_info linfo;
}
__attribute_packed;
struct cprElfHdr3 {
struct Elf_LE32_Ehdr ehdr;
struct Elf_LE32_Phdr phdr[3];
struct Elf32_Ehdr ehdr;
struct Elf32_Phdr phdr[3];
struct l_info linfo;
}
__attribute_packed;

View File

@ -45,8 +45,8 @@
PackUnix::PackUnix(InputFile *f) :
super(f), exetype(0), blocksize(0), overlay_offset(0), lsize(0)
{
COMPILE_TIME_ASSERT(sizeof(Elf_LE32_Ehdr) == 52);
COMPILE_TIME_ASSERT(sizeof(Elf_LE32_Phdr) == 32);
COMPILE_TIME_ASSERT(sizeof(Elf32_Ehdr) == 52);
COMPILE_TIME_ASSERT(sizeof(Elf32_Phdr) == 32);
COMPILE_TIME_ASSERT(sizeof(b_info) == 12);
COMPILE_TIME_ASSERT(sizeof(l_info) == 12);
COMPILE_TIME_ASSERT(sizeof(p_info) == 12);
@ -127,7 +127,7 @@ int PackUnix::getStrategy(Filter &/*ft*/)
// 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);
return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));
}
void PackUnix::pack2(OutputFile *fo, Filter &ft)
@ -222,6 +222,20 @@ void PackUnix::pack2(OutputFile *fo, Filter &ft)
}
}
void
PackUnix::patchLoaderChecksum()
{
unsigned char *const ptr = const_cast<unsigned char *>(getLoader());
l_info *const lp = &linfo;
// checksum for loader; also some PackHeader info
lp->l_magic = UPX_MAGIC_LE32; // LE32 always
lp->l_lsize = (unsigned short) lsize;
lp->l_version = (unsigned char) ph.version;
lp->l_format = (unsigned char) ph.format;
// INFO: lp->l_checksum is currently unused
lp->l_checksum = upx_adler32(ptr, lsize);
}
void PackUnix::pack3(OutputFile *fo, Filter &ft)
{
upx_byte const *p = getLoader();
@ -285,6 +299,158 @@ void PackUnix::pack(OutputFile *fo)
}
void PackUnix::packExtent(
const Extent &x,
unsigned &total_in,
unsigned &total_out,
Filter *ft,
OutputFile *fo
)
{
fi->seek(x.offset, SEEK_SET);
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) {
break;
}
rest -= l;
// 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;
unsigned end_u_adler = 0;
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(ibuf, ph.u_len, ph.u_adler);
ft->buf_len = l;
// compressWithFilters() requirements?
ph.filter = 0;
ph.filter_cto = 0;
ft->id = 0;
ft->cto = 0;
compressWithFilters(ft, OVERHEAD, strategy);
}
else {
(void) compress(ibuf, obuf); // ignore return value
}
if (ph.c_len < ph.u_len) {
ph.overlap_overhead = OVERHEAD;
if (!testOverlappingDecompression(obuf, ph.overlap_overhead)) {
// not in-place compressible
ph.c_len = ph.u_len;
}
}
if (ph.c_len >= ph.u_len) {
// block is not compressible
ph.c_len = ph.u_len;
// must update checksum of compressed data
ph.c_adler = upx_adler32(ibuf, ph.u_len, ph.saved_c_adler);
}
// write block sizes
b_info tmp;
memset(&tmp, 0, sizeof(tmp));
set_native32(&tmp.sz_unc, ph.u_len);
set_native32(&tmp.sz_cpr, ph.c_len);
if (ph.c_len < ph.u_len) {
tmp.b_method = (unsigned char) ph.method;
if (ft) {
tmp.b_ftid = (unsigned char) ft->id;
tmp.b_cto8 = ft->cto;
}
}
fo->write(&tmp, sizeof(tmp));
b_len += sizeof(b_info);
// write compressed data
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);
}
if (ft) {
ph.u_adler = end_u_adler;
}
total_in += ph.u_len;
total_out += ph.c_len;
}
}
void PackUnix::unpackExtent(unsigned wanted, OutputFile *fo,
unsigned &total_in, unsigned &total_out,
unsigned &c_adler, unsigned &u_adler,
bool first_PF_X, unsigned szb_info
)
{
b_info hdr; memset(&hdr, 0, sizeof(hdr));
while (wanted) {
fi->readx(&hdr, szb_info);
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();
break;
}
if (sz_unc <= 0 || sz_cpr <= 0)
throwCompressedDataViolation();
if (sz_cpr > sz_unc || sz_unc > (int)blocksize)
throwCompressedDataViolation();
int j = blocksize + OVERHEAD - sz_cpr;
fi->readx(ibuf+j, sz_cpr);
// update checksum of compressed data
c_adler = upx_adler32(ibuf + j, sz_cpr, c_adler);
// decompress
if (sz_cpr < sz_unc)
{
decompress(ibuf+j, ibuf, false);
if (12==szb_info) { // modern per-block filter
if (hdr.b_ftid) {
Filter ft(ph.level); // FIXME: ph.level for b_info?
ft.init(hdr.b_ftid, 0);
ft.cto = hdr.b_cto8;
ft.unfilter(ibuf, sz_unc);
}
}
else { // ancient per-file filter
if (first_PF_X) { // Elf32_Ehdr is never filtered
first_PF_X = false; // but everything else might be
}
else if (ph.filter) {
Filter ft(ph.level);
ft.init(ph.filter, 0);
ft.cto = (unsigned char) ph.filter_cto;
ft.unfilter(ibuf, sz_unc);
}
}
j = 0;
}
// update checksum of uncompressed data
u_adler = upx_adler32(ibuf + j, sz_unc, u_adler);
total_in += sz_cpr;
total_out += sz_unc;
// write block
if (fo)
fo->write(ibuf + j, sz_unc);
wanted -= sz_unc;
}
}
/*************************************************************************
// Generic Unix canUnpack().
**************************************************************************/
@ -321,7 +487,7 @@ void PackUnix::unpack(OutputFile *fo)
{
unsigned szb_info = sizeof(b_info);
{
Elf_LE32_Ehdr ehdr;
Elf32_Ehdr ehdr;
fi->seek(0, SEEK_SET);
fi->readx(&ehdr, sizeof(ehdr));
unsigned const e_entry = get_native32(&ehdr.e_entry);
@ -329,7 +495,7 @@ void PackUnix::unpack(OutputFile *fo)
szb_info = 2*sizeof(unsigned);
}
else {
Elf_LE32_Phdr phdr;
Elf32_Phdr phdr;
fi->seek(get_native32(&ehdr.e_phoff), SEEK_SET);
fi->readx(&phdr, sizeof(phdr));
unsigned const p_vaddr = get_native32(&phdr.p_vaddr);

View File

@ -59,19 +59,32 @@ protected:
virtual void pack4(OutputFile *, Filter &); // append PackHeader
virtual void patchLoader() = 0;
virtual void patchLoaderChecksum() {}
virtual void patchLoaderChecksum();
virtual void updateLoader(OutputFile *) = 0;
virtual void writePackHeader(OutputFile *fo);
// in order too share as much code as possible we introduce
// an endian abstraction here
virtual unsigned get_native32(const void *) = 0;
virtual void set_native32(void *, unsigned) = 0;
virtual void set_native16(void *, unsigned) = 0;
virtual unsigned get_native32(const void *) const = 0;
virtual unsigned get_native16(const void *) const = 0;
virtual void set_native32(void *, unsigned) const = 0;
virtual void set_native16(void *, unsigned) const = 0;
virtual bool checkCompressionRatio(unsigned, unsigned) const;
protected:
struct Extent {
off_t offset;
off_t size;
};
virtual void packExtent(const Extent &x,
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, unsigned szb_info );
int exetype;
unsigned blocksize;
unsigned progid; // program id
@ -94,7 +107,6 @@ protected:
unsigned char b_unused;
}
__attribute_packed;
struct l_info { // 12-byte trailer in header for loader
unsigned l_checksum;
unsigned l_magic;
@ -111,6 +123,8 @@ protected:
}
__attribute_packed;
struct l_info linfo;
// do not change !!!
enum { OVERHEAD = 2048 };
};
@ -120,24 +134,42 @@ protected:
// abstract classes encapsulating endian issues
// note: UPX_MAGIC is always stored in le32 format
**************************************************************************/
class PackUnixBe32 : public PackUnix
{
typedef PackUnix super;
protected:
PackUnixBe32(InputFile *f) : super(f) { }
virtual unsigned get_native32(const void *b)
{
return get_be32(b);
virtual unsigned get_native32(const void *b) const { return get_be32(b); }
virtual unsigned get_native16(const void *b) const { return get_be16(b); }
virtual void set_native32(void *b, unsigned v) const { set_be32(b, v); }
virtual void set_native16(void *b, unsigned v) const { set_be16(b, v); }
// must agree with stub/linux.hh
struct b_info { // 12-byte header before each compressed block
BE32 sz_unc; // uncompressed_size
BE32 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;
}
virtual void set_native32(void *b, unsigned v)
{
set_be32(b, v);
__attribute_packed;
struct l_info { // 12-byte trailer in header for loader
BE32 l_checksum;
BE32 l_magic;
BE16 l_lsize;
unsigned char l_version;
unsigned char l_format;
}
virtual void set_native16(void *b, unsigned v)
{
set_be16(b, v);
__attribute_packed;
struct p_info { // 12-byte packed program header
BE32 p_progid;
BE32 p_filesize;
BE32 p_blocksize;
}
__attribute_packed;
};
@ -146,18 +178,37 @@ class PackUnixLe32 : public PackUnix
typedef PackUnix super;
protected:
PackUnixLe32(InputFile *f) : super(f) { }
virtual unsigned get_native32(const void *b)
{
return get_le32(b);
virtual unsigned get_native32(const void *b) const { return get_le32(b); }
virtual unsigned get_native16(const void *b) const { return get_le16(b); }
virtual void set_native32(void *b, unsigned v) const { set_le32(b, v); }
virtual void set_native16(void *b, unsigned v) const { set_le16(b, v); }
// must agree with stub/linux.hh
struct b_info { // 12-byte header before each compressed block
LE32 sz_unc; // uncompressed_size
LE32 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;
}
virtual void set_native32(void *b, unsigned v)
{
set_le32(b, v);
__attribute_packed;
struct l_info { // 12-byte trailer in header for loader
LE32 l_checksum;
LE32 l_magic;
LE16 l_lsize;
unsigned char l_version;
unsigned char l_format;
}
virtual void set_native16(void *b, unsigned v)
{
set_le16(b, v);
__attribute_packed;
struct p_info { // 12-byte packed program header
LE32 p_progid;
LE32 p_filesize;
LE32 p_blocksize;
}
__attribute_packed;
};

View File

@ -72,10 +72,10 @@ const int *PackVmlinuxI386::getFilters() const
static int __acc_cdecl_qsort
compare_Phdr(void const *aa, void const *bb)
{
Elf_LE32_Phdr const *const a = (Elf_LE32_Phdr const *)aa;
Elf_LE32_Phdr const *const b = (Elf_LE32_Phdr const *)bb;
unsigned const xa = a->p_type - Elf_LE32_Phdr::PT_LOAD;
unsigned const xb = b->p_type - Elf_LE32_Phdr::PT_LOAD;
Elf32_Phdr const *const a = (Elf32_Phdr const *)aa;
Elf32_Phdr const *const b = (Elf32_Phdr const *)bb;
unsigned const xa = a->p_type - Elf32_Phdr::PT_LOAD;
unsigned const xb = b->p_type - Elf32_Phdr::PT_LOAD;
if (xa < xb) return -1; // PT_LOAD first
if (xa > xb) return 1;
if (a->p_paddr < b->p_paddr) return -1; // ascending by .p_paddr
@ -118,14 +118,14 @@ bool PackVmlinuxI386::canPack()
// additional requirements for vmlinux
if (ehdri.e_ehsize != sizeof(ehdri) // different <elf.h> ?
|| ehdri.e_phoff != sizeof(ehdri) // Phdrs not contiguous with Ehdr
|| ehdri.e_phentsize!=sizeof(Elf_LE32_Phdr)
|| ehdri.e_type!=Elf_LE32_Ehdr::ET_EXEC
|| ehdri.e_phentsize!=sizeof(Elf32_Phdr)
|| ehdri.e_type!=Elf32_Ehdr::ET_EXEC
|| 0x00100000!=(0x001fffff & ehdri.e_entry) // entry not an odd 1MB
) {
return false;
}
phdri = new Elf_LE32_Phdr[(unsigned) ehdri.e_phnum];
phdri = new Elf32_Phdr[(unsigned) ehdri.e_phnum];
fi->seek(ehdri.e_phoff, SEEK_SET);
fi->readx(phdri, ehdri.e_phnum * sizeof(*phdri));
@ -134,7 +134,7 @@ bool PackVmlinuxI386::canPack()
// Check that PT_LOADs form one contiguous chunk of the file.
for (unsigned j = 0; j < ehdri.e_phnum; ++j) {
if (Elf_LE32_Phdr::PT_LOAD==phdri[j].p_type) {
if (Elf32_Phdr::PT_LOAD==phdri[j].p_type) {
if (0xfff & (phdri[j].p_offset | phdri[j].p_paddr
| phdri[j].p_align | phdri[j].p_vaddr) ) {
return false;
@ -182,13 +182,13 @@ int PackVmlinuxI386::buildLoader(const Filter *ft)
void PackVmlinuxI386::pack(OutputFile *fo)
{
unsigned fo_off = 0;
Elf_LE32_Ehdr ehdro;
Elf32_Ehdr ehdro;
LE32 tmp_le32;
// NULL
// .text(PT_LOADs) .note(1st page) .note(rest)
// .shstrtab /* .symtab .strtab */
Elf_LE32_Shdr shdro[1+3+1/*+2*/];
Elf32_Shdr shdro[1+3+1/*+2*/];
memset(shdro, 0, sizeof(shdro));
char const shstrtab[]= "\0.text\0.note\0.shstrtab\0.symtab\0.strtab";
char const *p = shstrtab;
@ -198,7 +198,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
// .e_ident, .e_machine, .e_version, .e_flags
memcpy(&ehdro, &ehdri, sizeof(ehdro));
ehdro.e_type = Elf_LE32_Ehdr::ET_REL;
ehdro.e_type = Elf32_Ehdr::ET_REL;
ehdro.e_entry = 0;
ehdro.e_phoff = 0;
ehdro.e_shoff = 0; // later
@ -231,8 +231,8 @@ void PackVmlinuxI386::pack(OutputFile *fo)
while (0!=*p++) ;
shdro[1].sh_name = ptr_diff(p, shstrtab);
shdro[1].sh_type = Elf_LE32_Shdr::SHT_PROGBITS;
shdro[1].sh_flags = Elf_LE32_Shdr::SHF_ALLOC | Elf_LE32_Shdr::SHF_EXECINSTR;
shdro[1].sh_type = Elf32_Shdr::SHT_PROGBITS;
shdro[1].sh_flags = Elf32_Shdr::SHF_ALLOC | Elf32_Shdr::SHF_EXECINSTR;
shdro[1].sh_offset = fo_off;
shdro[1].sh_size = 1+ 4+ ph.c_len + lsize;
shdro[1].sh_addralign = 1;
@ -257,7 +257,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
while (0!=*p++) ;
shdro[2].sh_name = ptr_diff(p, shstrtab);
shdro[2].sh_type = Elf_LE32_Shdr::SHT_NOTE;
shdro[2].sh_type = Elf32_Shdr::SHT_NOTE;
shdro[2].sh_offset = fo_off;
shdro[2].sh_size = sizeof(ph.u_len) + ph.c_len;
shdro[2].sh_addralign = 1;
@ -283,7 +283,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
// while (0!=*p++) ; // name is the same
shdro[3].sh_name = ptr_diff(p, shstrtab);
shdro[3].sh_type = Elf_LE32_Shdr::SHT_NOTE;
shdro[3].sh_type = Elf32_Shdr::SHT_NOTE;
shdro[3].sh_offset = fo_off;
shdro[3].sh_size = sizeof(ph.u_len) + ph.c_len;
shdro[3].sh_addralign = 1;
@ -292,7 +292,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
while (0!=*p++) ;
shdro[4].sh_name = ptr_diff(p, shstrtab);
shdro[4].sh_type = Elf_LE32_Shdr::SHT_STRTAB;
shdro[4].sh_type = Elf32_Shdr::SHT_STRTAB;
shdro[4].sh_offset = fo_off;
shdro[4].sh_size = 1+ sizeof(shstrtab); // 1+: terminating '\0'
shdro[4].sh_addralign = 1;
@ -302,7 +302,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
while (0!=*p++) ;
fo_off = ~3 & (3+ fo_off);
shdro[5].sh_name = ptr_diff(p, shstrtab);
shdro[5].sh_type = Elf_LE32_Shdr::SHT_SYMTAB;
shdro[5].sh_type = Elf32_Shdr::SHT_SYMTAB;
shdro[5].sh_offset = fo_off;
shdro[5].sh_size = 16; // XXX ?
shdro[5].sh_link = 6; // to .strtab for symbols
@ -313,7 +313,7 @@ void PackVmlinuxI386::pack(OutputFile *fo)
while (0!=*p++) ;
shdro[6].sh_name = ptr_diff(p, shstrtab);
shdro[6].sh_type = Elf_LE32_Shdr::SHT_STRTAB;
shdro[6].sh_type = Elf32_Shdr::SHT_STRTAB;
shdro[6].sh_offset = fo_off;
shdro[6].sh_size = 1; // XXX ?
shdro[6].sh_addralign = 1;
@ -347,21 +347,21 @@ int PackVmlinuxI386::canUnpack()
|| !memcmp(&ehdri.e_ident[8], "FreeBSD", 7) // branded
|| ehdri.e_machine != 3 // Intel 80386
|| ehdri.e_version != 1 // version
|| ehdri.e_type != Elf_LE32_Ehdr::ET_REL
|| ehdri.e_type != Elf32_Ehdr::ET_REL
|| ehdri.e_shnum < 4
|| (unsigned)file_size < (ehdri.e_shnum * sizeof(Elf_LE32_Shdr) + ehdri.e_shoff)
|| (unsigned)file_size < (ehdri.e_shnum * sizeof(Elf32_Shdr) + ehdri.e_shoff)
)
return false;
// find the .shstrtab section
char shstrtab[40];
Elf_LE32_Shdr *p, *p_shstrtab=0;
shdri = new Elf_LE32_Shdr[(unsigned) ehdri.e_shnum];
Elf32_Shdr *p, *p_shstrtab=0;
shdri = new Elf32_Shdr[(unsigned) ehdri.e_shnum];
fi->seek(ehdri.e_shoff, SEEK_SET);
fi->readx(shdri, ehdri.e_shnum * sizeof(*shdri));
int j;
for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) {
if (Elf_LE32_Shdr::SHT_STRTAB==p->sh_type
if (Elf32_Shdr::SHT_STRTAB==p->sh_type
&& p->sh_size <= sizeof(shstrtab)
&& (p->sh_size + p->sh_offset) <= (unsigned) file_size
&& (10+ p->sh_name) <= p->sh_size // 1+ strlen(".shstrtab")

View File

@ -60,12 +60,12 @@ protected:
int n_ptload;
unsigned sz_ptload;
Elf_LE32_Phdr *phdri; // from input file
Elf_LE32_Shdr *shdri; // from input file
Elf_LE32_Shdr *p_text;
Elf_LE32_Shdr *p_note0;
Elf_LE32_Shdr *p_note1;
Elf_LE32_Ehdr ehdri; // from input file
Elf32_Phdr *phdri; // from input file
Elf32_Shdr *shdri; // from input file
Elf32_Shdr *p_text;
Elf32_Shdr *p_note0;
Elf32_Shdr *p_note1;
Elf32_Ehdr ehdri; // from input file
};