From 664a82e7c9359d5cb1b377d596fb04df50a83542 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Sun, 20 Feb 2005 22:57:04 +0000 Subject: [PATCH] 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 1108940224 +0000 --- src/p_elf.h | 141 ++++++++ src/p_lx_elf.cpp | 895 ++++++++++++++++++++++++++++++++++------------- src/p_lx_elf.h | 130 ++++++- src/p_lx_exc.cpp | 79 +++-- src/p_lx_exc.h | 17 +- src/p_unix.cpp | 176 +++++++++- src/p_unix.h | 99 ++++-- src/p_vmlinx.cpp | 46 +-- src/p_vmlinx.h | 12 +- 9 files changed, 1249 insertions(+), 346 deletions(-) diff --git a/src/p_elf.h b/src/p_elf.h index 6e724c88..cfcef310 100644 --- a/src/p_elf.h +++ b/src/p_elf.h @@ -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 */ diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 74c19b52..e4a3841b 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -38,117 +38,239 @@ #include "p_lx_exc.h" #include "p_lx_elf.h" -#define PT_LOAD Elf_LE32_Phdr::PT_LOAD +#define PT_LOAD Elf32_Phdr::PT_LOAD -/************************************************************************* -// -**************************************************************************/ +int +PackLinuxElf32::checkEhdr( + Elf32_Ehdr const *ehdr, + unsigned char e_machine, + unsigned char ei_class, + unsigned char ei_data +) const +{ + const unsigned char * const buf = ehdr->e_ident; -static const -#include "stub/l_lx_elf86.h" -static const -#include "stub/fold_elf86.h" + if (0!=memcmp(buf, "\x7f\x45\x4c\x46", 4) // "\177ELF" + || buf[Elf32_Ehdr::EI_CLASS]!=ei_class + || buf[Elf32_Ehdr::EI_DATA] !=ei_data ) { + return -1; + } + if (!memcmp(buf+8, "FreeBSD", 7)) // branded + return 1; + if (get_native16(&ehdr->e_type) != Elf32_Ehdr::ET_EXEC) + return 2; + if (get_native16(&ehdr->e_machine) != e_machine) + return 3; + if (get_native32(&ehdr->e_version) != Elf32_Ehdr::EV_CURRENT) + return 4; + if (get_native16(&ehdr->e_phnum) < 1) + return 5; + if (get_native16(&ehdr->e_phentsize) != sizeof(Elf32_Phdr)) + return 6; -PackLinuxI386elf::PackLinuxI386elf(InputFile *f) : - super(f), phdri(NULL) + // check for Linux kernels + unsigned const entry = get_native32(&ehdr->e_entry); + if (entry == 0xC0100000) // uncompressed vmlinux + return 1000; + if (entry == 0x00001000) // compressed vmlinux + return 1001; + if (entry == 0x00100000) // compressed bvmlinux + return 1002; + + // FIXME: add more checks for kernels + + // FIXME: add special checks for other ELF i386 formats, like + // NetBSD, OpenBSD, Solaris, .... + + // success + return 0; +} + +PackLinuxElf32::PackLinuxElf32(InputFile *f) + : super(f), phdri(NULL) { } -PackLinuxI386elf::~PackLinuxI386elf() +PackLinuxElf32::~PackLinuxElf32() { delete[] phdri; } int const * -PackLinuxI386elf::getFilters() const +PackLinuxElf32::getCompressionMethods(int method, int level) const +{ + // No real dependency on LE32. + return Packer::getDefaultCompressionMethods_le32(method, level); +} + +int const * +PackLinuxElf32ppc::getCompressionMethods(int /*method*/, int /*level*/) const +{ + // No real dependency on LE32. + static const int m_nrv2e[] = { M_NRV2E_LE32, -1 }; + return m_nrv2e; +} + +int const * +PackLinuxElf32ppc::getFilters() const { static const int filters[] = { - 0x49, 0x46, -// FIXME 2002-11-11: We use stub/fold_elf86.asm, which calls the -// decompressor multiple times, and unfilter is independent of decompress. -// Currently only filters 0x49, 0x46, 0x80..0x87 can handle this; -// and 0x80..0x87 are regarded as "untested". -#if 0 - 0x26, 0x24, 0x11, 0x14, 0x13, 0x16, 0x25, 0x15, 0x12, -#endif -#if 0 - 0x83, 0x36, 0x26, - 0x86, 0x80, - 0x84, 0x87, 0x81, - 0x82, 0x85, - 0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12, -#endif - -1 }; + 0xd0, -1 + }; return filters; } -int -PackLinuxI386elf::buildLoader(const Filter *ft) +void PackLinuxElf32::patchLoader() { } + +void PackLinuxElf32::updateLoader(OutputFile *fo) { - unsigned char tmp[sizeof(linux_i386elf_fold)]; - memcpy(tmp, linux_i386elf_fold, sizeof(linux_i386elf_fold)); - checkPatch(NULL, 0, 0, 0); // reset - if (opt->o_unix.ptinterp) { - unsigned j; - for (j = 0; j < sizeof(linux_i386elf_fold)-1; ++j) { - if (0x60==tmp[ j] - && 0x47==tmp[1+j] ) { - /* put INC EDI before PUSHA: inhibits auxv_up for PT_INTERP */ - tmp[ j] = 0x47; - tmp[1+j] = 0x60; - break; - } - } - } - return buildLinuxLoader( - linux_i386elf_loader, sizeof(linux_i386elf_loader), - tmp, sizeof(linux_i386elf_fold), ft ); + set_native32(&elfout.ehdr.e_entry, fo->getBytesWritten() + + get_native32(&elfout.phdr[0].p_vaddr)); } - -void PackLinuxI386elf::patchLoader() { } - - -bool PackLinuxI386elf::canPack() +int +PackLinuxElf32::buildLinuxLoader( + upx_byte const *const /*proto*/, + unsigned const /*szproto*/, + upx_byte const *const /*fold*/, + unsigned const /*szfold*/, + Filter const */*ft*/ +) { - unsigned char buf[sizeof(Elf_LE32_Ehdr) + 14*sizeof(Elf_LE32_Phdr)]; + return 0; +} + +PackLinuxElf32ppc::PackLinuxElf32ppc(InputFile *f) + : super(f) +{ +} + +PackLinuxElf32ppc::~PackLinuxElf32ppc() +{ +} + +static unsigned +umax(unsigned a, unsigned b) +{ + if (a <= b) { + return b; + } + return a; +} + +int +PackLinuxElf32ppc::buildLinuxLoader( + upx_byte const *const proto, + unsigned const szproto, + upx_byte const *const fold, + unsigned const szfold, + Filter const */*ft*/ +) +{ + int eof_empty = -1; + initLoader(&eof_empty, 4096, 0, 0); + + struct b_info h; memset(&h, 0, sizeof(h)); + unsigned fold_hdrlen = 0; + unsigned sz_unc, sz_cpr; + if (0 < szfold) { + cprElfHdr1 const *const hf = (cprElfHdr1 const *)fold; + fold_hdrlen = umax(0x80, sizeof(hf->ehdr) + + get_native16(&hf->ehdr.e_phentsize) * get_native16(&hf->ehdr.e_phnum) + + sizeof(l_info) ); + sz_unc = ((szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen)); + set_native32(&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) + sz_unc]; + if (0 < szfold) { + int r = upx_compress(uncLoader, sz_unc, sizeof(h) + cprLoader, &sz_cpr, + NULL, ph.method, 10, NULL, NULL ); + set_native32(&h.sz_cpr, sz_cpr); + if (r != UPX_E_OK || sz_cpr >= sz_unc) + throwInternalError("loader compression failed"); + } + memcpy(cprLoader, &h, sizeof(h)); + + // This adds the definition to the "library", to be used later. + linker->addSection("FOLDEXEC", cprLoader, sizeof(h) + sz_cpr); + delete [] cprLoader; + + //int const GAP = 128; // must match stub/l_mac_ppc.S + //segcmdo.vmsize += sz_unc - sz_cpr + GAP + 64; + + linker->addSection("ELFPPC32", proto, szproto); + + addLoader("ELFPPC32", 0); + addLoader("FOLDEXEC", 0); + return getLoaderSize(); +} + +static const +#include "stub/l_lx_elfppc32.h" + +static const +#include "stub/fold_elfppc32.h" + +int +PackLinuxElf32ppc::buildLoader(const Filter *ft) +{ + return buildLinuxLoader( + linux_elfppc32_loader, sizeof(linux_elfppc32_loader), + linux_elfppc32_fold, sizeof(linux_elfppc32_fold), ft ); +} + +bool +PackLinuxElf32ppc::canPack() +{ + unsigned char buf[sizeof(Elf32_Ehdr) + 14*sizeof(Elf32_Phdr)]; COMPILE_TIME_ASSERT(sizeof(buf) <= 512); exetype = 0; fi->readx(buf, sizeof(buf)); fi->seek(0, SEEK_SET); - Elf_LE32_Ehdr const *const ehdr = (Elf_LE32_Ehdr const *)buf; + Elf32_Ehdr const *const ehdr = (Elf32_Ehdr const *)buf; // now check the ELF header - if (checkEhdr(ehdr) != 0) + if (checkEhdr(ehdr, Elf32_Ehdr::EM_PPC, + Elf32_Ehdr::ELFCLASS32, Elf32_Ehdr::ELFDATA2MSB) != 0) return false; // additional requirements for linux/elf386 - if (ehdr->e_ehsize != sizeof(*ehdr)) { + if (get_native16(&ehdr->e_ehsize) != sizeof(*ehdr)) { throwCantPack("invalid Ehdr e_ehsize; try `--force-execve'"); return false; } - if (ehdr->e_phoff != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr + unsigned const e_phoff = get_native32(&ehdr->e_phoff); + if (e_phoff != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr throwCantPack("non-contiguous Ehdr/Phdr; try `--force-execve'"); return false; } // The first PT_LOAD must cover the beginning of the file (0==p_offset). - Elf_LE32_Phdr const *phdr = (Elf_LE32_Phdr const *)(buf + ehdr->e_phoff); - for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) { + unsigned const e_phnum = get_native16(&ehdr->e_phnum); + Elf32_Phdr const *phdr = (Elf32_Phdr const *)(buf + e_phoff); + for (unsigned j=0; j < e_phnum; ++phdr, ++j) { if (j >= 14) return false; - if (phdr->PT_LOAD == phdr->p_type) { - if (phdr->p_offset != 0) { - throwCantPack("invalid Phdr p_offset; try `--force-execve'"); - return false; - } + if (phdr->PT_LOAD == get_native32(&phdr->p_type)) { + // Just avoid the "rewind" when unpacking? + //if (phdr->p_offset != 0) { + // throwCantPack("invalid Phdr p_offset; try `--force-execve'"); + // return false; + //} + // detect possible conflict upon invocation - if (phdr->p_vaddr < (unsigned)(0x400000 + file_size) - || phdr->p_paddr < (unsigned)(0x400000 + file_size) ) { + unsigned const p_vaddr = get_native32(&phdr->p_vaddr); + if (p_vaddr < (unsigned)(0x400000 + file_size) + || p_vaddr < (unsigned)(0x400000 + file_size) ) { throwAlreadyPackedByUPX(); // not necessarily, but mostly true return false; } @@ -166,105 +288,99 @@ bool PackLinuxI386elf::canPack() return true; } -void PackLinuxI386elf::packExtent( - const Extent &x, - unsigned &total_in, - unsigned &total_out, - Filter *ft, - OutputFile *fo +off_t +PackLinuxElf32::getbrk(const Elf32_Phdr *phdr, int e_phnum) const +{ + off_t brka = 0; + for (int j = 0; j < e_phnum; ++phdr, ++j) { + if (PT_LOAD == get_native32(&phdr->p_type)) { + off_t b = get_native32(&phdr->p_vaddr) + get_native32(&phdr->p_memsz); + if (b > brka) + brka = b; + } + } + return brka; +} + +void +PackLinuxElf32::generateElfHdr( + OutputFile */*fo*/, + void const *proto, + unsigned const brka ) { - 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; + cprElfHdr2 *const h2 = (cprElfHdr2 *)&elfout; + cprElfHdr3 *const h3 = (cprElfHdr3 *)&elfout; + memcpy(h3, proto, sizeof(*h3)); // reads beyond, but OK - // Note: compression for a block can fail if the - // file is e.g. blocksize + 1 bytes long + assert(get_native32(&h2->ehdr.e_phoff) == sizeof(Elf32_Ehdr)); + h2->ehdr.e_shoff = 0; + assert(get_native16(&h2->ehdr.e_ehsize) == sizeof(Elf32_Ehdr)); + assert(get_native16(&h2->ehdr.e_phentsize) == sizeof(Elf32_Phdr)); + h2->ehdr.e_shnum = 0; - // 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(ft, OVERHEAD, strategy); - } - else { - (void) compress(ibuf, obuf); // ignore return value - } +#if 0 //{ + unsigned identsize; + char const *const ident = getIdentstr(&identsize); +#endif //} + sz_elf_hdrs = sizeof(*h2) - sizeof(linfo); // default + set_native32(&h2->phdr[0].p_filesz, sizeof(*h2)); // + identsize; + h2->phdr[0].p_memsz = h2->phdr[0].p_filesz; - 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; + // Info for OS kernel to set the brk() + if (brka) { + set_native32(&h2->phdr[1].p_type, PT_LOAD); // be sure + set_native32(&h2->phdr[1].p_offset, 0xfff&brka); + set_native32(&h2->phdr[1].p_vaddr, brka); + set_native32(&h2->phdr[1].p_paddr, brka); + h2->phdr[1].p_filesz = 0; + h2->phdr[1].p_memsz = 0; } } +void +PackLinuxElf32ppc::generateElfHdr( + OutputFile *fo, + void const *proto, + unsigned const brka +) +{ + super::generateElfHdr(fo, proto, brka); -void PackLinuxI386elf::pack1(OutputFile *fo, Filter &) + if (ph.format==UPX_F_LINUX_ELF_PPC) { + cprElfHdr2 *const h2 = (cprElfHdr2 *)&elfout; + assert(2==get_native16(&h2->ehdr.e_phnum)); + set_native32(&h2->phdr[0].p_flags, Elf32_Phdr::PF_W | get_native32(&h2->phdr[0].p_flags)); + memset(&h2->linfo, 0, sizeof(h2->linfo)); + fo->write(h2, sizeof(*h2)); + } + else { + assert(false); // unknown ph.format, PackLinuxElf32ppc::generateElfHdr + } +} + +static const +#include "stub/l_lx_elf86.h" +static const +#include "stub/fold_elf86.h" + +void PackLinuxElf32::pack1(OutputFile *fo, Filter &/*ft*/) { fi->seek(0, SEEK_SET); fi->readx(&ehdri, sizeof(ehdri)); - assert(ehdri.e_phoff == sizeof(Elf_LE32_Ehdr)); // checked by canPack() - sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize; + unsigned const e_phoff = get_native32(&ehdri.e_phoff); + unsigned const e_phnum = get_native16(&ehdri.e_phnum); + assert(e_phoff == sizeof(Elf32_Ehdr)); // checked by canPack() + sz_phdrs = e_phnum * get_native16(&ehdri.e_phentsize); - phdri = new Elf_LE32_Phdr[(unsigned)ehdri.e_phnum]; - fi->seek(ehdri.e_phoff, SEEK_SET); + phdri = new Elf32_Phdr[e_phnum]; + fi->seek(e_phoff, SEEK_SET); fi->readx(phdri, sz_phdrs); - generateElfHdr(fo, linux_i386elf_fold, getbrk(phdri, ehdri.e_phnum) ); + generateElfHdr(fo, linux_elfppc32_fold, getbrk(phdri, e_phnum) ); } -void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft) +void PackLinuxElf32::pack2(OutputFile *fo, Filter &ft) { Extent x; unsigned k; @@ -272,10 +388,11 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft) // count passes, set ptload vars ui_total_passes = 0; off_t ptload0hi = 0, ptload1lo = 0, ptload1sz = 0; - for (k = 0; k < ehdri.e_phnum; ++k) { - if (PT_LOAD == phdri[k].p_type) { - x.offset = phdri[k].p_offset; - x.size = phdri[k].p_filesz; + unsigned const e_phnum = get_native16(&ehdri.e_phnum); + for (k = 0; k < e_phnum; ++k) { + if (PT_LOAD == get_native32(&phdri[k].p_type)) { + x.offset = get_native32(&phdri[k].p_offset); + x.size = get_native32(&phdri[k].p_filesz); if (0 == ptload0hi) { ptload0hi = x.offset + x.size; } @@ -295,7 +412,7 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft) ui_pass = -1; // Compressing Elf headers is invisible to UI. x.offset = 0; - x.size = sizeof(Elf_LE32_Ehdr) + sz_phdrs; + x.size = sizeof(Elf32_Ehdr) + sz_phdrs; { int const old_level = ph.level; ph.level = 10; packExtent(x, total_in, total_out, 0, fo); @@ -306,22 +423,25 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft) ft.addvalue = 0; int nx = 0; - for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) { + for (k = 0; k < e_phnum; ++k) if (PT_LOAD==get_native32(&phdri[k].p_type)) { if (ft.id < 0x40) { // FIXME: ?? ft.addvalue = phdri[k].p_vaddr; } - x.offset = phdri[k].p_offset; - x.size = phdri[k].p_filesz; + x.offset = get_native32(&phdri[k].p_offset); + x.size = get_native32(&phdri[k].p_filesz); if (0 == nx) { // 1st PT_LOAD must cover Ehdr at 0==p_offset - unsigned const delta = sizeof(Elf_LE32_Ehdr) + sz_phdrs; + unsigned const delta = sizeof(Elf32_Ehdr) + sz_phdrs; if (ft.id < 0x40) { // FIXME: ?? ft.addvalue += delta; } x.offset += delta; x.size -= delta; } + // compressWithFilters() always assumes a "loader", so would + // throw NotCompressible for small .data Extents, which PowerPC + // sometimes marks as PF_X anyway. So filter only first segment. packExtent(x, total_in, total_out, - ((Elf_LE32_Phdr::PF_X & phdri[k].p_flags) + ((0==nx && (Elf32_Phdr::PF_X & get_native32(&phdri[k].p_flags))) ? &ft : 0 ), fo ); ++nx; } @@ -338,100 +458,50 @@ void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft) if ((off_t)total_in != file_size) throwEOFException(); + set_native32(&elfout.phdr[0].p_filesz, fo->getBytesWritten()); } -void PackLinuxI386elf::pack3(OutputFile *fo, Filter &ft) +void PackLinuxElf32ppc::pack3(OutputFile *fo, Filter &ft) { - // We have packed multiple blocks, so PackLinuxI386::buildLinuxLoader - // needs an adjusted ph.c_len in order to get alignment correct. - unsigned const save_c_len = ph.c_len; - ph.c_len = fo->getBytesWritten() - ( - // 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) ? (unsigned) elfout.phdr[2].p_memsz : 0u) + - // p_progid, p_filesize, p_blocksize - sizeof(p_info) + - // compressed data - b_len ); - buildLoader(&ft); /* redo for final .align constraints */ - ph.c_len = save_c_len; + unsigned disp; + unsigned const zero = 0; + unsigned len = fo->getBytesWritten(); + fo->write(&zero, 3& -len); // align to 0 mod 4 + len += (3& -len) + sizeof(disp); + set_native32(&disp, 4+ len - sz_elf_hdrs); // 4: sizeof(instruction) + fo->write(&disp, sizeof(disp)); + super::pack3(fo, ft); } -void PackLinuxI386elf::unpackExtent(unsigned wanted, OutputFile *fo, - unsigned &total_in, unsigned &total_out, - unsigned &c_adler, unsigned &u_adler, - bool first_PF_X, unsigned szb_info -) + +void PackLinuxElf32::pack4(OutputFile *fo, Filter &ft) { - 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; + overlay_offset = sz_elf_hdrs; + unsigned const zero = 0; + unsigned len = fo->getBytesWritten(); + fo->write(&zero, 3& -len); // align to 0 mod 4 + len += 3& -len; + set_native32(&elfout.phdr[0].p_filesz, len); + super::pack4(fo, ft); // write PackHeader and overlay_offset - 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(); +#define PAGE_MASK (~0u<<12) + // pre-calculate for benefit of runtime disappearing act via munmap() + set_native32(&elfout.phdr[0].p_memsz, PAGE_MASK & (~PAGE_MASK + len)); +#undef PAGE_MASK - 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; - } + // rewrite Elf header + fo->seek(0, SEEK_SET); + fo->rewrite(&elfout, overlay_offset); + fo->rewrite(&linfo, sizeof(linfo)); } - -void PackLinuxI386elf::unpack(OutputFile *fo) +void PackLinuxElf32::unpack(OutputFile *fo) { #define MAX_ELF_HDR 512 char bufehdr[MAX_ELF_HDR]; - Elf_LE32_Ehdr *const ehdr = (Elf_LE32_Ehdr *)bufehdr; - Elf_LE32_Phdr const *phdr = (Elf_LE32_Phdr *)(1+ehdr); + Elf32_Ehdr *const ehdr = (Elf32_Ehdr *)bufehdr; + Elf32_Phdr const *phdr = (Elf32_Phdr *)(1+ehdr); unsigned szb_info = sizeof(b_info); { @@ -482,7 +552,352 @@ void PackLinuxI386elf::unpack(OutputFile *fo) } if (fo) fo->seek(phdr->p_offset, SEEK_SET); - if (Elf_LE32_Phdr::PF_X & phdr->p_flags) { + if (Elf32_Phdr::PF_X & phdr->p_flags) { + unpackExtent(phdr->p_filesz, fo, total_in, total_out, + c_adler, u_adler, first_PF_X, szb_info); + first_PF_X = false; + } + else { + unpackExtent(phdr->p_filesz, fo, total_in, total_out, + c_adler, u_adler, false, szb_info); + } + } + } + + if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole? + if (fo) + fo->seek(ptload0hi, SEEK_SET); + unpackExtent(ptload1lo - ptload0hi, fo, total_in, total_out, + c_adler, u_adler, false, szb_info); + } + if (total_out != orig_file_size) { // non-PT_LOAD stuff + if (fo) + fo->seek(0, SEEK_END); + unpackExtent(orig_file_size - total_out, fo, total_in, total_out, + c_adler, u_adler, false, szb_info); + } + + // check for end-of-file + fi->readx(&bhdr, szb_info); + 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(&bhdr.sz_cpr); + if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic + throwCompressedDataViolation(); + } + else { // extra bytes after end? + throwCompressedDataViolation(); + } + + // update header with totals + ph.c_len = total_in; + ph.u_len = total_out; + + // all bytes must be written + if (total_out != orig_file_size) + throwEOFException(); + + // finally test the checksums + if (ph.c_adler != c_adler || ph.u_adler != u_adler) + throwChecksumError(); +#undef MAX_ELF_HDR +} +/************************************************************************* +// +**************************************************************************/ + + +PackLinuxI386elf::PackLinuxI386elf(InputFile *f) : + super(f), phdri(NULL) +{ +} + +PackLinuxI386elf::~PackLinuxI386elf() +{ + delete[] phdri; +} + +int const * +PackLinuxI386elf::getFilters() const +{ + static const int filters[] = { + 0x49, 0x46, +// FIXME 2002-11-11: We use stub/fold_elf86.asm, which calls the +// decompressor multiple times, and unfilter is independent of decompress. +// Currently only filters 0x49, 0x46, 0x80..0x87 can handle this; +// and 0x80..0x87 are regarded as "untested". +#if 0 + 0x26, 0x24, 0x11, 0x14, 0x13, 0x16, 0x25, 0x15, 0x12, +#endif +#if 0 + 0x83, 0x36, 0x26, + 0x86, 0x80, + 0x84, 0x87, 0x81, + 0x82, 0x85, + 0x24, 0x16, 0x13, 0x14, 0x11, 0x25, 0x15, 0x12, +#endif + -1 }; + return filters; +} + +int +PackLinuxI386elf::buildLoader(const Filter *ft) +{ + unsigned char tmp[sizeof(linux_i386elf_fold)]; + memcpy(tmp, linux_i386elf_fold, sizeof(linux_i386elf_fold)); + checkPatch(NULL, 0, 0, 0); // reset + if (opt->o_unix.is_ptinterp) { + unsigned j; + for (j = 0; j < sizeof(linux_i386elf_fold)-1; ++j) { + if (0x60==tmp[ j] + && 0x47==tmp[1+j] ) { + /* put INC EDI before PUSHA: inhibits auxv_up for PT_INTERP */ + tmp[ j] = 0x47; + tmp[1+j] = 0x60; + break; + } + } + } + return buildLinuxLoader( + linux_i386elf_loader, sizeof(linux_i386elf_loader), + tmp, sizeof(linux_i386elf_fold), ft ); +} + + +void PackLinuxI386elf::patchLoader() { } + + +bool PackLinuxI386elf::canPack() +{ + unsigned char buf[sizeof(Elf32_Ehdr) + 14*sizeof(Elf32_Phdr)]; + COMPILE_TIME_ASSERT(sizeof(buf) <= 512); + + exetype = 0; + + fi->readx(buf, sizeof(buf)); + fi->seek(0, SEEK_SET); + Elf32_Ehdr const *const ehdr = (Elf32_Ehdr const *)buf; + + // now check the ELF header + if (checkEhdr(ehdr) != 0) + return false; + + // additional requirements for linux/elf386 + if (ehdr->e_ehsize != sizeof(*ehdr)) { + throwCantPack("invalid Ehdr e_ehsize; try `--force-execve'"); + return false; + } + if (ehdr->e_phoff != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr + throwCantPack("non-contiguous Ehdr/Phdr; try `--force-execve'"); + return false; + } + + // The first PT_LOAD must cover the beginning of the file (0==p_offset). + Elf32_Phdr const *phdr = (Elf32_Phdr const *)(buf + ehdr->e_phoff); + for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) { + if (j >= 14) + return false; + if (phdr->PT_LOAD == phdr->p_type) { + if (phdr->p_offset != 0) { + throwCantPack("invalid Phdr p_offset; try `--force-execve'"); + return false; + } + + // detect possible conflict upon invocation + if (phdr->p_vaddr < (unsigned)(0x400000 + file_size) + || phdr->p_paddr < (unsigned)(0x400000 + file_size) ) { + throwAlreadyPackedByUPX(); // not necessarily, but mostly true + return false; + } + exetype = 1; + break; + } + } + + if (!super::canPack()) + return false; + assert(exetype == 1); + + // set options + opt->o_unix.blocksize = blocksize = file_size; + return true; +} + + +void PackLinuxI386elf::pack1(OutputFile *fo, Filter &) +{ + fi->seek(0, SEEK_SET); + fi->readx(&ehdri, sizeof(ehdri)); + assert(ehdri.e_phoff == sizeof(Elf32_Ehdr)); // checked by canPack() + sz_phdrs = ehdri.e_phnum * ehdri.e_phentsize; + + phdri = new Elf32_Phdr[(unsigned)ehdri.e_phnum]; + fi->seek(ehdri.e_phoff, SEEK_SET); + fi->readx(phdri, sz_phdrs); + + generateElfHdr(fo, linux_i386elf_fold, getbrk(phdri, ehdri.e_phnum) ); +} + +void PackLinuxI386elf::pack2(OutputFile *fo, Filter &ft) +{ + Extent x; + unsigned k; + + // count passes, set ptload vars + ui_total_passes = 0; + off_t ptload0hi = 0, ptload1lo = 0, ptload1sz = 0; + for (k = 0; k < ehdri.e_phnum; ++k) { + if (PT_LOAD == phdri[k].p_type) { + x.offset = phdri[k].p_offset; + x.size = phdri[k].p_filesz; + if (0 == ptload0hi) { + ptload0hi = x.offset + x.size; + } + else if (0 == ptload1lo) { + ptload1lo = x.offset; + ptload1sz = x.size; + } + ui_total_passes++; + } + } + if (0!=ptload1sz && ptload0hi < ptload1lo) + ui_total_passes++; + + // compress extents + unsigned total_in = 0; + unsigned total_out = 0; + + ui_pass = -1; // Compressing Elf headers is invisible to UI. + x.offset = 0; + x.size = sizeof(Elf32_Ehdr) + sz_phdrs; + { + int const old_level = ph.level; ph.level = 10; + packExtent(x, total_in, total_out, 0, fo); + ph.level = old_level; + } + + ui_pass = 0; + ft.addvalue = 0; + + int nx = 0; + for (k = 0; k < ehdri.e_phnum; ++k) if (PT_LOAD==phdri[k].p_type) { + if (ft.id < 0x40) { + // FIXME: ?? ft.addvalue = phdri[k].p_vaddr; + } + x.offset = phdri[k].p_offset; + x.size = phdri[k].p_filesz; + if (0 == nx) { // 1st PT_LOAD must cover Ehdr at 0==p_offset + unsigned const delta = sizeof(Elf32_Ehdr) + sz_phdrs; + if (ft.id < 0x40) { + // FIXME: ?? ft.addvalue += delta; + } + x.offset += delta; + x.size -= delta; + } + packExtent(x, total_in, total_out, + ((Elf32_Phdr::PF_X & phdri[k].p_flags) + ? &ft : 0 ), fo ); + ++nx; + } + if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole? + x.offset = ptload0hi; + x.size = ptload1lo - ptload0hi; + 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, fo); + } + + if ((off_t)total_in != file_size) + throwEOFException(); + elfout.phdr[0].p_filesz = fo->getBytesWritten(); +} + +void PackLinuxI386elf::pack3(OutputFile *fo, Filter &ft) +{ + // We have packed multiple blocks, so PackLinuxI386::buildLinuxLoader + // needs an adjusted ph.c_len in order to get alignment correct. + unsigned const save_c_len = ph.c_len; + ph.c_len = fo->getBytesWritten() - ( + // 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) ? (unsigned) elfout.phdr[2].p_memsz : 0u) + + // p_progid, p_filesize, p_blocksize + sizeof(p_info) + + // compressed data + b_len ); + buildLoader(&ft); /* redo for final .align constraints */ + ph.c_len = save_c_len; + super::pack3(fo, ft); +} + + +void PackLinuxI386elf::unpack(OutputFile *fo) +{ +#define MAX_ELF_HDR 512 + char bufehdr[MAX_ELF_HDR]; + Elf32_Ehdr *const ehdr = (Elf32_Ehdr *)bufehdr; + Elf32_Phdr const *phdr = (Elf32_Phdr *)(1+ehdr); + + unsigned szb_info = sizeof(b_info); + { + fi->seek(0, SEEK_SET); + fi->readx(bufehdr, MAX_ELF_HDR); + unsigned const e_entry = get_native32(&ehdr->e_entry); + if (e_entry < 0x401180) { /* old style, 8-byte b_info */ + szb_info = 2*sizeof(unsigned); + } + } + + fi->seek(overlay_offset, SEEK_SET); + p_info hbuf; + fi->readx(&hbuf, sizeof(hbuf)); + unsigned orig_file_size = get_native32(&hbuf.p_filesize); + blocksize = get_native32(&hbuf.p_blocksize); + if (file_size > (off_t)orig_file_size || blocksize > orig_file_size) + throwCantUnpack("file header corrupted"); + + ibuf.alloc(blocksize + OVERHEAD); + b_info bhdr; memset(&bhdr, 0, sizeof(bhdr)); + fi->readx(&bhdr, szb_info); + 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); + decompress(ibuf, (upx_byte *)ehdr, false); + + unsigned total_in = 0; + unsigned total_out = 0; + unsigned c_adler = upx_adler32(NULL, 0); + unsigned u_adler = upx_adler32(NULL, 0); + off_t ptload0hi=0, ptload1lo=0, ptload1sz=0; + + // decompress PT_LOAD + bool first_PF_X = true; + fi->seek(- (off_t) (szb_info + ph.c_len), SEEK_CUR); + for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) { + if (PT_LOAD==phdr->p_type) { + if (0==ptload0hi) { + ptload0hi = phdr->p_filesz + phdr->p_offset; + } + else if (0==ptload1lo) { + ptload1lo = phdr->p_offset; + ptload1sz = phdr->p_filesz; + } + if (fo) + fo->seek(phdr->p_offset, SEEK_SET); + if (Elf32_Phdr::PF_X & phdr->p_flags) { unpackExtent(phdr->p_filesz, fo, total_in, total_out, c_adler, u_adler, first_PF_X, szb_info); first_PF_X = false; diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index 7e32f563..bd00eac2 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -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[] }; diff --git a/src/p_lx_exc.cpp b/src/p_lx_exc.cpp index 04f7d374..354bee7f 100644 --- a/src/p_lx_exc.cpp +++ b/src/p_lx_exc.cpp @@ -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)); diff --git a/src/p_lx_exc.h b/src/p_lx_exc.h index f49117a3..3349c0e0 100644 --- a/src/p_lx_exc.h +++ b/src/p_lx_exc.h @@ -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; diff --git a/src/p_unix.cpp b/src/p_unix.cpp index f2aadc8c..57fcef93 100644 --- a/src/p_unix.cpp +++ b/src/p_unix.cpp @@ -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(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); diff --git a/src/p_unix.h b/src/p_unix.h index ef235d9b..1efd2f7b 100644 --- a/src/p_unix.h +++ b/src/p_unix.h @@ -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; + }; diff --git a/src/p_vmlinx.cpp b/src/p_vmlinx.cpp index 695ac41d..f3ac1fbd 100644 --- a/src/p_vmlinx.cpp +++ b/src/p_vmlinx.cpp @@ -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 ? || 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") diff --git a/src/p_vmlinx.h b/src/p_vmlinx.h index 6570a911..0f4a4c02 100644 --- a/src/p_vmlinx.h +++ b/src/p_vmlinx.h @@ -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 };