⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 p_vmlinx.cpp

📁 UPX 源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/* p_vmlinx.cpp -- pack vmlinux ET_EXEC file (before bootsect or setup)   This file is part of the UPX executable compressor.   Copyright (C) 2004-2007 John Reiser   Copyright (C) 1996-2007 Markus Franz Xaver Johannes Oberhumer   Copyright (C) 1996-2007 Laszlo Molnar   All Rights Reserved.   UPX and the UCL library are free software; you can redistribute them   and/or modify them under the terms of the GNU General Public License as   published by the Free Software Foundation; either version 2 of   the License, or (at your option) any later version.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; see the file COPYING.   If not, write to the Free Software Foundation, Inc.,   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.   Markus F.X.J. Oberhumer   Laszlo Molnar   markus@oberhumer.com      ml1050@users.sourceforge.net   John Reiser   jreiser@users.sourceforge.net */#include "conf.h"#include "file.h"#include "filter.h"#include "packer.h"#include "p_vmlinx.h"#include "linker.h"static const#include "stub/i386-linux.kernel.vmlinux.h"static const#include "stub/amd64-linux.kernel.vmlinux.h"static const#include "stub/arm-linux.kernel.vmlinux.h"static const#include "stub/armeb-linux.kernel.vmlinux.h"static const#include "stub/powerpc-linux.kernel.vmlinux.h"/*************************************************************************//**************************************************************************/template <class T>PackVmlinuxBase<T>::PackVmlinuxBase(InputFile *f,                                    unsigned e_machine, unsigned elfclass, unsigned elfdata,                                    char const *const boot_label) :    super(f),    my_e_machine(e_machine), my_elfclass(elfclass), my_elfdata(elfdata),    my_boot_label(boot_label),    n_ptload(0), phdri(NULL), shdri(NULL), shstrtab(NULL){    ElfClass::compileTimeAssertions();    bele = N_BELE_CTP::getRTP<BeLePolicy>();}template <class T>PackVmlinuxBase<T>::~PackVmlinuxBase(){    delete [] phdri;    delete [] shdri;    delete [] shstrtab;}template <class T>int PackVmlinuxBase<T>::getStrategy(Filter &/*ft*/){    // Called just before reading and compressing each block.    // Might want to adjust blocksize, etc.    // If user specified the filter, then use it (-2==strategy).    // Else try the first two filters, and pick the better (2==strategy).    return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));}template <class T>int __acc_cdecl_qsortPackVmlinuxBase<T>::compare_Phdr(void const *aa, void const *bb){    Phdr const *const a = (Phdr const *)aa;    Phdr const *const b = (Phdr const *)bb;    unsigned const xa = a->p_type - Phdr::PT_LOAD;    unsigned const xb = b->p_type - 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    if (a->p_paddr > b->p_paddr) return  1;                                 return  0;}template <class T>typename T::Shdr const *PackVmlinuxBase<T>::getElfSections(){    Shdr const *p, *shstrsec=0;    shdri = new 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 (Shdr::SHT_STRTAB==p->sh_type        &&  (p->sh_size + p->sh_offset) <= (unsigned) file_size        &&  (10+ p->sh_name) <= p->sh_size  // 1+ strlen(".shstrtab")        ) {            delete [] shstrtab;            shstrtab = new char[1+ p->sh_size];            fi->seek(p->sh_offset, SEEK_SET);            fi->readx(shstrtab, p->sh_size);            shstrtab[p->sh_size] = '\0';            if (0==strcmp(".shstrtab", shstrtab + p->sh_name)) {                shstrsec = p;                break;            }        }    }    return shstrsec;}template <class T>bool PackVmlinuxBase<T>::canPack(){    fi->seek(0, SEEK_SET);    fi->readx(&ehdri, sizeof(ehdri));    // now check the ELF header    if (memcmp(&ehdri, "\x7f\x45\x4c\x46", 4)    ||  ehdri.e_ident[Ehdr::EI_CLASS] != my_elfclass    ||  ehdri.e_ident[Ehdr::EI_DATA] != my_elfdata    ||  ehdri.e_ident[Ehdr::EI_VERSION] != Ehdr::EV_CURRENT    ||  !memcmp(&ehdri.e_ident[8], "FreeBSD", 7)  // branded    ||  ehdri.e_machine != my_e_machine    ||  ehdri.e_version != 1  // version    ||  ehdri.e_ehsize != sizeof(ehdri)  // different <elf.h> ?    ) {        return false;    }    // additional requirements for vmlinux    if (ehdri.e_type != Ehdr::ET_EXEC    ||  ehdri.e_phoff != sizeof(ehdri)  // Phdr not contiguous with Ehdr    ||  ehdri.e_phentsize!=sizeof(Phdr)    ||  !is_valid_e_entry(ehdri.e_entry)    ) {        return false;    }    // A Linux kernel must have a __ksymtab section. [??]    Shdr const *p, *const shstrsec = getElfSections();    if (0==shstrsec) {        return false;    }    {        int j;        for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) {            if (Shdr::SHT_PROGBITS==p->sh_type            && 0==strcmp("__ksymtab", p->sh_name + shstrtab)) {                break;            }        }        if (j < 0) {            return false;        }    }    phdri = new Phdr[(unsigned) ehdri.e_phnum];    fi->seek(ehdri.e_phoff, SEEK_SET);    fi->readx(phdri, ehdri.e_phnum * sizeof(*phdri));    // Put PT_LOAD together at the beginning, ascending by .p_paddr.    qsort(phdri, ehdri.e_phnum, sizeof(*phdri), compare_Phdr);    // Find convex hull of physical addresses, and count the PT_LOAD.    // Ignore ".bss": .p_filesz < .p_memsz    unsigned phys_lo= ~0u, phys_hi= 0u;    for (unsigned j = 0; j < ehdri.e_phnum; ++j) {        if (Phdr::PT_LOAD==phdri[j].p_type) {            // Check for general sanity (not necessarily required.)            if (0xfff & (phdri[j].p_offset | phdri[j].p_paddr                       | phdri[j].p_align  | phdri[j].p_vaddr) ) {                return false;            }            if (phys_lo > phdri[j].p_paddr) {                phys_lo = phdri[j].p_paddr;            }            if (phys_hi < (phdri[j].p_filesz + phdri[j].p_paddr)) {                phys_hi = (phdri[j].p_filesz + phdri[j].p_paddr);            }            ++n_ptload;        }    }    paddr_min = phys_lo;    sz_ptload = phys_hi - phys_lo;    return 0 < n_ptload;}#include "p_elf.h"template <class T>void PackVmlinuxBase<T>::pack(OutputFile *fo){    unsigned fo_off = 0;    Ehdr ehdro;    U32 tmp_u32;    // NULL    // .text(PT_LOADs) .note(1st page) .note(rest)    // .shstrtab .symtab .strtab    Shdr shdro[1+3+3];    memset(shdro, 0, sizeof(shdro));    ibuf.alloc(file_size);    obuf.allocForCompression(file_size);    // .e_ident, .e_machine, .e_version, .e_flags    memcpy(&ehdro, &ehdri, sizeof(ehdro));    ehdro.e_type = Ehdr::ET_REL;    ehdro.e_entry = 0;    ehdro.e_phoff = 0;    ehdro.e_shoff = sizeof(ehdro);    ehdro.e_phentsize = 0;    ehdro.e_phnum = 0;    ehdro.e_shnum = 1+3+3;    ehdro.e_shstrndx = 4;    fo->write(&ehdro, sizeof(ehdro)); fo_off+= sizeof(ehdro);    fo->write(shdro, sizeof(shdro)); fo_off+= sizeof(shdro);// Notice overlap [containment] of physical PT_LOAD[2] into PTLOAD[1]// in this vmlinux for x86_64 from Fedora Core 6 on 2007-01-07://Program Headers://  Type           Offset             VirtAddr           PhysAddr//                 FileSiz            MemSiz              Flags  Align//  LOAD           0x0000000000200000 0xffffffff80200000 0x0000000000200000//                 0x000000000034bce8 0x000000000034bce8  R E    200000//  LOAD           0x000000000054c000 0xffffffff8054c000 0x000000000054c000//                 0x00000000000ed004 0x00000000001702a4  RWE    200000//  LOAD           0x0000000000800000 0xffffffffff600000 0x00000000005f5000//                 0x0000000000000c08 0x0000000000000c08  RWE    200000//  NOTE           0x0000000000000000 0x0000000000000000 0x0000000000000000//                 0x0000000000000000 0x0000000000000000  R      8// Therefore we must "compose" the convex hull to be loaded.    ph.u_len = sz_ptload;    memset(ibuf, 0, sz_ptload);    for (unsigned j = 0; j < ehdri.e_phnum; ++j) {        if (Phdr::PT_LOAD==phdri[j].p_type) {            fi->seek(phdri[j].p_offset, SEEK_SET);            fi->readx(ibuf + ((unsigned) phdri[j].p_paddr - paddr_min), phdri[j].p_filesz);        }    }    checkAlreadyPacked(ibuf + ph.u_len - 1024, 1024);    // prepare filter    ph.filter = 0;    Filter ft(ph.level);    ft.buf_len = ph.u_len;    ft.addvalue = 0;  // we are independent of actual runtime address; see ckt32    upx_compress_config_t cconf; cconf.reset();    // limit stack size needed for runtime decompression    cconf.conf_lzma.max_num_probs = 1846 + (768 << 4); // ushort: ~28KB stack    unsigned ppc32_extra = 0;    if (Ehdr::EM_PPC==my_e_machine) {        // output layout:        //      .long UPX_MAGIC_LE32        //      .long L20 - L10        // L10:        //      b_info for Ehdr; compressed Ehdr; .balign 4  // one block only        //      b_info for LOAD; compressed LOAD; .balign 4  // possibly many blocks        //          // This allows per-block filters!        // L20:        //      b f_decompress        // +4:  f_unfilter(char *buf, unsigned len, unsigned cto8, unsigned ftid)        //          // Code for multiple filters can "daisy chain" on ftid.        //      f_decompress(char const *src, unsigned  src_len,        //                   char       *dst, unsigned *dst_len, int method)        unsigned tmp;        tmp = UPX_MAGIC_LE32; fo->write(&tmp, sizeof(tmp)); fo_off += sizeof(tmp);        tmp = 0;              fo->write(&tmp, sizeof(tmp)); fo_off += sizeof(tmp);        ppc32_extra += 2*sizeof(tmp);        unsigned const len_unc = sizeof(ehdri) + sizeof(Phdr) * ehdri.e_phnum;        MemBuffer unc_hdr(len_unc);        MemBuffer cpr_hdr; cpr_hdr.allocForCompression(len_unc);        memcpy(&unc_hdr[0],             &ehdri, sizeof(ehdri));        memcpy(&unc_hdr[sizeof(ehdri)],  phdri, sizeof(Phdr) * ehdri.e_phnum);        unsigned len_cpr = 0;        int const r = upx_compress(unc_hdr, len_unc, cpr_hdr, &len_cpr,            NULL, ph.method, 10, NULL, NULL );        if (UPX_E_OK!=r || len_unc<=len_cpr)  // FIXME: allow no compression            throwInternalError("Ehdr compression failed");        struct b_info { // 12-byte header before each compressed block            unsigned sz_unc;  // uncompressed_size            unsigned sz_cpr;  //   compressed_size            unsigned char b_method;  // compression algorithm            unsigned char b_ftid;  // filter id            unsigned char b_cto8;  // filter parameter            unsigned char b_unused;  // FIXME: !=0  for partial-block unfilter            // unsigned f_offset, f_len;  // only if    partial-block unfilter        }        __attribute_packed;        struct b_info hdr_info;        set_be32(&hdr_info.sz_unc, len_unc);        set_be32(&hdr_info.sz_cpr, len_cpr);        hdr_info.b_method = ph.method;        hdr_info.b_ftid = 0;        hdr_info.b_cto8 = 0;        hdr_info.b_unused = 0;        fo->write(&hdr_info, sizeof(hdr_info)); fo_off += sizeof(hdr_info);        unsigned const frag = (3& (0u-len_cpr));        ppc32_extra += sizeof(hdr_info) + len_cpr + frag;        fo_off += len_cpr + frag;        fo->write(cpr_hdr, len_cpr + frag);        // Partial filter: .text and following contiguous SHF_EXECINSTR        upx_bytep f_ptr = ibuf;        unsigned  f_len = 0;        Shdr const *shdr = 1+ shdri;  // skip empty shdr[0]        if (ft.buf_len==0  // not specified yet  FIXME: was set near construction        && (Shdr::SHF_ALLOC     & shdr->sh_flags)        && (Shdr::SHF_EXECINSTR & shdr->sh_flags)) {            // shdr[1] is instructions (probably .text)            f_ptr = ibuf + (unsigned) (shdr->sh_offset - phdri[0].p_offset);            f_len = shdr->sh_size;            ++shdr;            for (int j= ehdri.e_shnum - 2; --j>=0; ++shdr) {                unsigned prev_end = shdr[-1].sh_size + shdr[-1].sh_offset;                prev_end += ~(0u-shdr[0].sh_addralign) & (0u-prev_end);  // align_up                if ((Shdr::SHF_ALLOC     & shdr->sh_flags)                &&  (Shdr::SHF_EXECINSTR & shdr->sh_flags)                &&  shdr[0].sh_offset==prev_end) {                    f_len += shdr->sh_size;                }                else {                    break;                }            }        }        else { // ft.buf_len already specified, or Shdr[1] not instructions            f_ptr = ibuf;            f_len = ph.u_len;        }        compressWithFilters(ibuf, ph.u_len, obuf,            f_ptr, f_len,  // filter range            NULL, 0,  // hdr_ptr, hdr_len            &ft, 512, &cconf, getStrategy(ft));        set_be32(&hdr_info.sz_unc, ph.u_len);        set_be32(&hdr_info.sz_cpr, ph.c_len);        hdr_info.b_ftid = ft.id;        hdr_info.b_cto8 = ft.cto;        if (ph.u_len!=f_len) {            hdr_info.b_unused = 1;  // flag for partial filter

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -