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 };