From 5d331fdf69abbe21cfa69f4328ef7a6d6c217792 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Mon, 12 Jul 2004 17:21:07 +0000 Subject: [PATCH] new file format vmlinux/i386 Modified Files: Makefile conf.h help.cpp linker.cpp p_elf.h packer.cpp packerf.cpp packmast.cpp stub/Makefile stub/l_vmlinz.asm Added Files: p_vmlinx.h p_vmlinx.cpp stub/l_vmlinx.asm committer: jreiser 1089652867 +0000 --- src/Makefile | 2 +- src/conf.h | 1 + src/help.cpp | 1 + src/linker.cpp | 7 +- src/p_elf.h | 9 + src/p_vmlinx.cpp | 486 ++++++++++++++++++++++++++++++++++++++++++ src/p_vmlinx.h | 76 +++++++ src/packerf.cpp | 1 + src/packmast.cpp | 4 + src/stub/Makefile | 7 +- src/stub/l_vmlinx.asm | 142 ++++++++++++ src/stub/l_vmlinz.asm | 2 +- 12 files changed, 732 insertions(+), 6 deletions(-) create mode 100644 src/p_vmlinx.cpp create mode 100644 src/p_vmlinx.h create mode 100644 src/stub/l_vmlinx.asm diff --git a/src/Makefile b/src/Makefile index ab13c7a4..2bd70a31 100644 --- a/src/Makefile +++ b/src/Makefile @@ -52,7 +52,7 @@ OBJECTS1 = \ p_com$o p_djgpp2$o p_elks$o p_exe$o \ p_lx_elf$o p_lx_exc$o p_lx_sep$o p_lx_sh$o \ p_ps1$o p_sys$o p_tmt$o p_tos$o \ - p_unix$o p_vmlinz$o p_w16ne$o p_w32pe$o p_wcle$o + p_unix$o p_vmlinz$o p_vmlinx$o p_w16ne$o p_w32pe$o p_wcle$o # no exceptions or RTTI OBJECTS2 = \ diff --git a/src/conf.h b/src/conf.h index 27a5b4b0..56f5a2ab 100644 --- a/src/conf.h +++ b/src/conf.h @@ -437,6 +437,7 @@ inline void operator delete[](void *p) #define UPX_F_BVMLINUZ_i386 16 #define UPX_F_ELKS_8086 17 #define UPX_F_PS1_EXE 18 +#define UPX_F_VMLINUX_i386 19 #define UPX_F_ATARI_TOS 129 #define UPX_F_SOLARIS_SPARC 130 diff --git a/src/help.cpp b/src/help.cpp index 819b41b0..e047723a 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -260,6 +260,7 @@ void show_help(int x) " rtm32/pe," " tmt/adam," "\n " + " vmlinux/386," " vmlinuz/386," " watcom/le," //" win16/ne," diff --git a/src/linker.cpp b/src/linker.cpp index 462f3b4a..f42bc385 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -57,7 +57,8 @@ Linker::Linker(const void *pdata, int plen, int pinfo) info = pinfo; njumps = nsections = frozen = 0; jumps = new jump[200]; - sections = new section[200]; +#define NSECTIONS 350 + sections = new section[NSECTIONS]; char *p = iloader + info; while (get32(p) != (unsigned)(-1)) @@ -68,7 +69,7 @@ Linker::Linker(const void *pdata, int plen, int pinfo) sections[nsections].istart = get32(p+8); sections[nsections++].ostart = -1; p += 12; - assert(nsections < 200); + assert(nsections < NSECTIONS); } else { @@ -154,7 +155,7 @@ void Linker::addSection(const char *sname, const void *sdata, unsigned len) sections[nsections].istart = ilen; sections[nsections].len = len; sections[nsections++].ostart = olen; - assert(nsections < 200); + assert(nsections < NSECTIONS); memcpy(iloader+ilen,sdata,len); ilen += len; } diff --git a/src/p_elf.h b/src/p_elf.h index 2f6d52db..4022afd8 100644 --- a/src/p_elf.h +++ b/src/p_elf.h @@ -51,6 +51,15 @@ struct Elf_LE32_Ehdr LE16 e_shentsize; /* Section header table entry size */ LE16 e_shnum; /* Section header table entry count */ LE16 e_shstrndx; /* Section header string table index */ + + // Values for e_type + enum { + 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 */ + }; } __attribute_packed; diff --git a/src/p_vmlinx.cpp b/src/p_vmlinx.cpp new file mode 100644 index 00000000..64c4c8b8 --- /dev/null +++ b/src/p_vmlinx.cpp @@ -0,0 +1,486 @@ +/* p_vmlinx.cpp -- pack vmlinux ET_EXEC file (before bootsect or setup) + + This file is part of the UPX executable compressor. + + Copyright (C) 2004 John Reiser + Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2004 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@cdata.tvnet.hu + + John Reiser + jreiser@users.sourceforge.net + */ + + +#include "conf.h" + +#include "file.h" +#include "filter.h" +#include "packer.h" +#include "p_vmlinx.h" + +static const +#include "stub/l_vmlinx.h" + +/************************************************************************* +// +**************************************************************************/ + +PackVmlinuxI386::PackVmlinuxI386(InputFile *f) : + super(f), shdri(NULL) +{ +} + +PackVmlinuxI386::~PackVmlinuxI386() +{ + delete [] shdri; +} + +const int *PackVmlinuxI386::getCompressionMethods(int method, int level) const +{ + return Packer::getDefaultCompressionMethods_le32(method, level); +} + + +const int *PackVmlinuxI386::getFilters() const +{ + static const int filters[] = { + 0x49, + -1 }; + return filters; +} + + +bool PackVmlinuxI386::canPack() +{ + fi->seek(0, SEEK_SET); + fi->readx(&ehdri, sizeof(ehdri)); + + // now check the ELF header + if (memcmp(&ehdri, "\x7f\x45\x4c\x46\x01\x01\x01", 7) // ELF 32-bit LSB + || !memcmp(&ehdri.e_ident[8], "FreeBSD", 7) // branded + || ehdri.e_machine != 3 // Intel 80386 + || ehdri.e_version != 1 // version + ) + return false; + + // additional requirements for vmlinux + if (ehdri.e_ehsize != sizeof(ehdri) // different ? + || ehdri.e_phoff != sizeof(ehdri) // Phdrs not contiguous with Ehdr + || ehdri.e_phnum!=2 || ehdri.e_phentsize!=sizeof(Elf_LE32_Phdr) + || ehdri.e_type!=Elf_LE32_Ehdr::ET_EXEC + || 0x00100000!=(0x001fffff & ehdri.e_entry) // entry not an odd 1MB + ) { + return false; + } + + fi->seek(ehdri.e_phoff, SEEK_SET); + fi->readx(phdri, sizeof(phdri)); + if (Elf_LE32_Phdr::PT_LOAD!=phdri[0].p_type || 0!=(0xfff & phdri[0].p_offset) + || Elf_LE32_Phdr::PT_LOAD!=phdri[1].p_type || 0!=(0xfff & phdri[1].p_offset) + || 0!=(0xfff & phdri[0].p_paddr) || 0!=(0xfff & phdri[0].p_vaddr) + || 0!=(0xfff & phdri[1].p_paddr) || 0!=(0xfff & phdri[1].p_vaddr) + || 0x1000!=phdri[0].p_offset + || phdri[1].p_offset!=(phdri[0].p_offset + (~0xfff & (0xfff + phdri[0].p_filesz))) + ) { + return false; + } + + return true; +} + +int PackVmlinuxI386::buildLoader(const Filter *ft) +{ + // prepare loader + initLoader(nrv_loader, sizeof(nrv_loader)); + addLoader("LINUX000", + (0x40==(0xf0 & ft->id)) ? "LXCKLLT1" : (ft->id ? "LXCALLT1" : ""), + "LXMOVEUP", + getDecompressor(), + NULL + ); + if (ft->id) + { + assert(ft->calls > 0); + if (0x40==(0xf0 & ft->id)) { + addLoader("LXCKLLT9", NULL); + } + else { + addLoader("LXCALLT9", NULL); + } + addFilter32(ft->id); + } + addLoader("LINUX990""IDENTSTR""UPX1HEAD", NULL); + return getLoaderSize(); +} + + +void PackVmlinuxI386::pack(OutputFile *fo) +{ + unsigned fo_off = 0; + Elf_LE32_Ehdr ehdro; + + // NULL + // .text(PT_LOADs) .note(1st page) .note(rest) + // .shstrtab /* .symtab .strtab */ + Elf_LE32_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; + + ibuf.alloc(file_size); + obuf.allocForCompression(file_size); + + // .e_ident, .e_machine, .e_version, .e_flags + memcpy(&ehdro, &ehdri, sizeof(ehdro)); + ehdro.e_type = Elf_LE32_Ehdr::ET_REL; + ehdro.e_entry = 0; + ehdro.e_phoff = 0; + ehdro.e_shoff = 0; // later + ehdro.e_phentsize = 0; + ehdro.e_phnum = 0; + ehdro.e_shnum = 1+3+1/*+2*/; + ehdro.e_shstrndx = 4; + fo->write(&ehdro, sizeof(ehdro)); fo_off+= sizeof(ehdro); + + // .data length + (.text length padded to PAGE_SIZE) + ph.u_len = phdri[1].p_filesz + (phdri[1].p_offset - phdri[0].p_offset); + fi->seek(phdri[0].p_offset, SEEK_SET); + fi->readx(ibuf, ph.u_len); + 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; + + compressWithFilters(&ft, 1 << 20); + + const unsigned lsize = getLoaderSize(); + MemBuffer loader(lsize); + memcpy(loader, getLoader(), lsize); + + patchPackHeader(loader, lsize); + patch_le32(loader, lsize, "ULEN", ph.u_len); + patchFilter32(loader, lsize, &ft); + + while (0!=*p++) ; + shdro[1].sh_name = 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_offset = fo_off; + shdro[1].sh_size = 1+ 4+ ph.c_len + lsize; + shdro[1].sh_addralign = 1; + + char const call = 0xE8; // opcode for CALL d32 + fo->write(&call, 1); fo_off+=1; + fo->write(&ph.c_len, sizeof(ph.c_len)); fo_off += 4; // XXX LE32 + fo->write(obuf, ph.c_len); fo_off += ph.c_len; + fo->write(loader, lsize); fo_off += lsize; + + verifyOverlappingDecompression(); + + // .note with 1st page -------------------------------- + fi->seek(0, SEEK_SET); + ph.u_len = phdri[0].p_offset; + fi->readx(ibuf, ph.u_len); + compress(ibuf, obuf); + + while (0!=*p++) ; + shdro[2].sh_name = p - shstrtab; + shdro[2].sh_type = Elf_LE32_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; + fo->write(&ph.u_len, sizeof(ph.u_len)); // XXX LE32 + fo->write(obuf, ph.c_len); fo_off += shdro[2].sh_size; + + // .note with rest -------------------------------- + fi->seek(phdri[1].p_offset + phdri[1].p_filesz, SEEK_SET); + ph.u_len = file_size - (phdri[1].p_offset + phdri[1].p_filesz); + fi->readx(ibuf, ph.u_len); + compress(ibuf, obuf); + + // while (0!=*p++) ; // name is the same + shdro[3].sh_name = p - shstrtab; + shdro[3].sh_type = Elf_LE32_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; + fo->write(&ph.u_len, sizeof(ph.u_len)); // XXX LE32 + fo->write(obuf, ph.c_len); fo_off += shdro[3].sh_size; + + while (0!=*p++) ; + shdro[4].sh_name = p - shstrtab; + shdro[4].sh_type = Elf_LE32_Shdr::SHT_STRTAB; + shdro[4].sh_offset = fo_off; + shdro[4].sh_size = 1+ sizeof(shstrtab); // 1+: terminating '\0' + shdro[4].sh_addralign = 1; + fo->write(shstrtab, shdro[4].sh_size); fo_off += shdro[4].sh_size; + +#if 0 /*{ no symbols! */ + while (0!=*p++) ; + fo_off = ~3 & (3+ fo_off); + shdro[5].sh_name = p - shstrtab; + shdro[5].sh_type = Elf_LE32_Shdr::SHT_SYMTAB; + shdro[5].sh_offset = fo_off; + shdro[5].sh_size = 16; // XXX ? + shdro[5].sh_link = 6; // to .strtab for symbols + shdro[5].sh_addralign = 4; + shdro[5].sh_entsize = 16; // XXX Elf32_Sym + fo->seek(fo_off, SEEK_SET); + fo->write("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16); fo_off += 16; + + while (0!=*p++) ; + shdro[6].sh_name = p - shstrtab; + shdro[6].sh_type = Elf_LE32_Shdr::SHT_STRTAB; + shdro[6].sh_offset = fo_off; + shdro[6].sh_size = 1; // XXX ? + shdro[6].sh_addralign = 1; + fo->write("", 1); fo_off += 1; +#endif /*}*/ + + fo_off = ~3 & (3+ fo_off); + fo->seek(fo_off, SEEK_SET); + ehdro.e_shoff = fo_off; + fo->write(shdro, sizeof(shdro)); + + fo->seek(0, SEEK_SET); + fo->write(&ehdro, sizeof(ehdro)); + + if (!checkFinalCompressionRatio(fo)) + throwNotCompressible(); +} + + +/************************************************************************* +// unpack +**************************************************************************/ + +int PackVmlinuxI386::canUnpack() +{ + fi->seek(0, SEEK_SET); + fi->readx(&ehdri, sizeof(ehdri)); + + // now check the ELF header + if (memcmp(&ehdri, "\x7f\x45\x4c\x46\x01\x01\x01", 7) // ELF 32-bit LSB + || !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_shnum < 4 + || file_size < (ehdri.e_shnum * sizeof(Elf_LE32_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[ehdri.e_shnum]; + fi->seek(ehdri.e_shoff, SEEK_SET); + fi->readx(shdri, ehdri.e_shnum * sizeof(Elf_LE32_Shdr)); + int j; + for (p = shdri, j= ehdri.e_shnum; --j>=0; ++p) { + if (Elf_LE32_Shdr::SHT_STRTAB==p->sh_type + && p->sh_size <= sizeof(shstrtab) + && (p->sh_size + p->sh_offset) <= file_size + && (10+ p->sh_name) <= p->sh_size // 1+ strlen(".shstrtab") + ) { + fi->seek(p->sh_offset, SEEK_SET); + fi->readx(shstrtab, p->sh_size); + if (0==strcmp(".shstrtab", &shstrtab[p->sh_name])) { + p_shstrtab = p; + break; + } + } + } + if (0==p_shstrtab) { + return false; + } + + // check for .text .note .note and sane (.sh_size + .sh_offset) + p_note0 = p_note1 = p_text = 0; + for (p= shdri, j= ehdri.e_shnum; --j>=0; ++p) { + if (file_size < (p->sh_size + p->sh_offset) + || p_shstrtab->sh_size < (5+ p->sh_name) ) { + continue; + } + if (0==strcmp(".text", &shstrtab[p->sh_name])) { + p_text = p; + } + if (0==strcmp(".note", &shstrtab[p->sh_name])) { + if (0==p_note0) { + p_note0 = p; + } else + if (0==p_note1) { + p_note1 = p; + } + } + } + if (0==p_text || 0==p_note0 || 0==p_note1) { + return false; + } + + char buf[1024]; + fi->seek(p_text->sh_offset + p_text->sh_size - sizeof(buf), SEEK_SET); + fi->readx(buf, sizeof(buf)); + if (!getPackHeader(buf, sizeof(buf))) + return false; + + return true; +} + + +void PackVmlinuxI386::unpack(OutputFile *fo) +{ + struct { + unsigned char opcode; + unsigned char d32[4]; + } call; + PackHeader const ph_tmp(ph); + + fi->seek(p_note0->sh_offset, SEEK_SET); + fi->readx(&ph.u_len, sizeof(ph.u_len)); // XXX LE32 + ibuf.alloc(ph.c_len = p_note0->sh_size - sizeof(ph.u_len)); + fi->readx(ibuf, ph.c_len); + obuf.allocForUncompression(ph.u_len); + decompress(ibuf, obuf, false); + fo->write(obuf, ph.u_len); + obuf.dealloc(); + ibuf.dealloc(); + + ph = ph_tmp; + fi->seek(p_text->sh_offset, SEEK_SET); + fi->readx(&call, 5); + if (0xE8!=call.opcode + || *(int *)&call.d32!=(int)ph.c_len // XXX LE32 + ) { + throwCantUnpack(".text corrupted"); + } + ibuf.alloc(ph.c_len); + fi->readx(ibuf, ph.c_len); + obuf.allocForUncompression(ph.u_len); + decompress(ibuf, obuf); + + Filter ft(ph.level); + ft.init(ph.filter, 0); + ft.cto = (unsigned char) ph.filter_cto; + ft.unfilter(obuf, ph.u_len); + fo->write(obuf, ph.u_len); + obuf.dealloc(); + ibuf.dealloc(); + + fi->seek(p_note1->sh_offset, SEEK_SET); + fi->readx(&ph.u_len, sizeof(ph.u_len)); // XXX LE32 + ibuf.alloc(ph.c_len = p_note1->sh_size - sizeof(ph.u_len)); + fi->readx(ibuf, p_note1->sh_size - sizeof(ph.u_len)); + obuf.allocForUncompression(ph.u_len); + decompress(ibuf, obuf, false); + fo->write(obuf, ph.u_len); + obuf.dealloc(); + ibuf.dealloc(); + + ph = ph_tmp; +} + +// +// Example usage within build system of Linux kernel-2.6.7: +// +//----- arch/i386/boot/compressed/Makefile +//# +//# linux/arch/i386/boot/compressed/Makefile +//# +//# create a compressed vmlinux image from the original vmlinux +//# +// +//targets := vmlinux upx-head.o upx-piggy.o +// +//LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 +// +//$(obj)/vmlinux: $(obj)/upx-head.o $(obj)/upx-piggy.o FORCE +// $(call if_changed,ld) +// @: +// +//$(obj)/upx-piggy.o: vmlinux FORCE +// rm -f $(obj)/upx-piggy.o +// upx -o $(obj)/upx-piggy.o $< +//----- +// +//----- arch/i386/boot/compressed/upx-head.S +//#include +// +// .text +//startup_32: .globl startup_32 +// pushl $0; popf # subsumes "cli; cld"; also clears NT for buggy BIOS +// +// pushl $ __BOOT_DS; pop %ds # %ds= __BOOT_DS +// push %ds; pop %es # %es= __BOOT_DS +// +// movl $ startup_32,%eax # base address of uncompressed execution +// pushl $ __BOOT_CS +///* Fall into .text of upx-compressed vmlinux. */ +//----- + +// +// Example test jig: +// gcc -o test-piggy -nostartfiles -nostdlib test-piggy.o piggy.o +// gdb test-piggy +// (gdb) run >dumped +//----- test-piggy.S +//#include +//#include +// +//dump: +// movl $0x456789,%edx # length MODIFY THIS VALUE TO SUIT YOUR CASE +// movl $0x100000,%ecx # base +// movl $1,%ebx # stdout +// movl $ __NR_write,%eax +// int $0x80 +// nop +// hlt +//mmap: +// pushl %ebx +// leal 2*4(%esp),%ebx +// pushl $ __NR_mmap; popl %eax +// int $0x80 +// popl %ebx +// ret $6*4 +// +//_start: .globl _start +// nop +// int3 # enter debugger! +// pushl $0 +// pushl $0 +// pushl $ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED +// pushl $ PROT_EXEC | PROT_WRITE | PROT_READ +// pushl $0x600000 # 6MB +// pushl $0x100000 # 1MB +// call mmap +// push %cs +///* Fall into .text of upx-compressed vmlinux. */ +//----- + +/* +vi:ts=4:et +*/ + + diff --git a/src/p_vmlinx.h b/src/p_vmlinx.h new file mode 100644 index 00000000..749e5dc8 --- /dev/null +++ b/src/p_vmlinx.h @@ -0,0 +1,76 @@ +/* p_vmlinx.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2004 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@cdata.tvnet.hu + */ + + +#ifndef __UPX_P_VMLINX_H +#define __UPX_P_VMLINX_H + +#include "p_elf.h" + +/************************************************************************* +// vmlinx/i386 (bare binary Linux kernel image) +**************************************************************************/ + +class PackVmlinuxI386 : public Packer +{ + typedef Packer super; +public: + PackVmlinuxI386(InputFile *f); + virtual ~PackVmlinuxI386(); + virtual int getVersion() const { return 13; } + virtual int getFormat() const { return UPX_F_VMLINUX_i386; } + virtual const char *getName() const { return "vmlinux/386"; } + virtual const int *getCompressionMethods(int method, int level) const; + virtual const int *getFilters() const; + + virtual void pack(OutputFile *fo); + virtual void unpack(OutputFile *fo); + + virtual bool canPack(); + virtual int canUnpack(); + +protected: + virtual int buildLoader(const Filter *ft); +// virtual const upx_byte *getLoader() const; +// virtual int getLoaderSize() const; + + Elf_LE32_Ehdr ehdri; // from input file + Elf_LE32_Phdr phdri[2]; // 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; +}; + + +#endif /* already included */ + + +/* +vi:ts=4:et +*/ + diff --git a/src/packerf.cpp b/src/packerf.cpp index d5dd84ff..bf00f99d 100644 --- a/src/packerf.cpp +++ b/src/packerf.cpp @@ -373,6 +373,7 @@ bool Packer::patchFilter32(void *loader, int lsize, const Filter *ft) if (ft->id < 0x80) { if (0x40 <= ft->id && ft->id < 0x50 && ( UPX_F_LINUX_i386 ==ph.format + || UPX_F_VMLINUX_i386 ==ph.format || UPX_F_VMLINUZ_i386 ==ph.format || UPX_F_BVMLINUZ_i386==ph.format ) ) { // "push byte '?'" diff --git a/src/packmast.cpp b/src/packmast.cpp index ede64e4f..9d4ac0ac 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -49,6 +49,7 @@ #include "p_w16ne.h" #include "p_w32pe.h" #include "p_vmlinz.h" +#include "p_vmlinx.h" #include "p_ps1.h" @@ -182,6 +183,8 @@ static Packer* try_packers(InputFile *f, try_function func) // // linux kernel // + if ((p = func(new PackVmlinuxI386(f),f)) != NULL) + return p; if ((p = func(new PackVmlinuzI386(f),f)) != NULL) return p; if ((p = func(new PackBvmlinuzI386(f),f)) != NULL) @@ -224,6 +227,7 @@ static Packer* try_packers(InputFile *f, try_function func) return p; if ((p = func(new PackCom(f),f)) != NULL) return p; + return NULL; } diff --git a/src/stub/Makefile b/src/stub/Makefile index 7372fbc1..af987e1a 100644 --- a/src/stub/Makefile +++ b/src/stub/Makefile @@ -35,7 +35,7 @@ STUBS = \ l_lx_exec86.h fold_exec86.h \ l_lx_elf86.h fold_elf86.h \ l_lx_sh86.h fold_sh86.h \ - l_vmlinz.h + l_vmlinz.h l_vmlinx.h # experimental: ifneq ($(strip $(wildcard $(srcdir)/l_ext2.asm)),) @@ -221,6 +221,10 @@ l_vmlinz.h: l_vmlinz.asx $(NASM) -f bin -o $T.bin $< $(BIN2H) $T.bin nrv_loader $@ +l_vmlinx.h: l_vmlinx.asx + $(NASM) -f bin -o $T.bin $< + $(BIN2H) $T.bin nrv_loader $@ + l_vxd.h: l_vxd.asx $(NASM) -f bin -o $T.bin $< $(BIN2H) $T.bin nrv_loader $@ @@ -398,6 +402,7 @@ l_t_n2e.h: n2e_d.ash bits.ash $(DEPS1) ../version.h l_t_n2es.h: n2e_d.ash bits.ash $(DEPS1) ../version.h l_tmt.h: $(DEPS2) $(DEPS3) l_vmlinz.h: $(DEPS2) $(DEPS3) +l_vmlinx.h: $(DEPS2) $(DEPS3) l_vxd.h: $(DEPS2) $(DEPS3) l_wcle.h: $(DEPS2) $(DEPS3) l_w32pe.h: $(DEPS2) $(DEPS3) diff --git a/src/stub/l_vmlinx.asm b/src/stub/l_vmlinx.asm new file mode 100644 index 00000000..010e1620 --- /dev/null +++ b/src/stub/l_vmlinx.asm @@ -0,0 +1,142 @@ +; l_vmlinx.asm -- loader & decompressor for the vmlinux/i386 format +; +; This file is part of the UPX executable compressor. +; +; Copyright (C) 1996-2004 Markus Franz Xaver Johannes Oberhumer +; Copyright (C) 1996-2004 Laszlo Molnar +; Copyright (C) 2004 John Reiser +; 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 +; +; +; John Reiser +; + + +%define jmps jmp short +%define jmpn jmp near +%include "macros.ash" + + BITS 32 + SECTION .text + ORG 0 + +; ============= +; ============= ENTRY POINT +; ============= + +start: +; In: +; %eax= &uncompressed [and final entry]; %ds= %es= __BOOT_DS +; %esp: &compressed; __BOOT_CS +; __LINUX000__ + pop edx ; &compressed; length at -4(%edx) + + push eax ; MATCH00(1/2) entry address; __BOOT_CS + push edi ; MATCH01 save + push esi ; MATCH02 save + +%ifdef __LXCALLT1__ + push eax ; MATCH03 src unfilter +%endif; __LXDUMMY0__ +%ifdef __LXCKLLT1__ + push eax ; MATCH03 src unfilter + push byte '?' ; MATCH04 cto unfilter +%endif; __LXMOVEUP__ + push 'ULEN' ; MATCH05 uncompressed length + call move_up ; MATCH06 + +; ============= +; ============= DECOMPRESSION +; ============= + +%include "n2b_d32.ash" +%include "n2d_d32.ash" +%include "n2e_d32.ash" +%include "cl1_d32.ash" + +; ============= +; ============= UNFILTER +; ============= + + pop ecx ; MATCH05 len +%ifdef __LXCKLLT9__ + pop edx ; MATCH04 cto + pop edi ; MATCH03 src + ckt32 edi, dl +%endif; __LXDUMMY2__ +%ifdef __LXCALLT9__ + pop edi ; MATCH03 src + cjt32 0 +%endif; __LINUX990__ + pop esi ; MATCH02 restore + pop edi ; MATCH01 restore + xor ebx, ebx ; booting the 1st cpu + retf ; MATCH00 set cs + +%define UNLAP 0x10 +%define ALIGN (~0<<4) + ; must have 0==(UNLAP &~ ALIGN) + +move_up: + pop esi ; MATCH06 &decompressor + mov ecx,[-4+ esi] ; length of decompressor+unfilter + mov ebp,eax ; &uncompressed + add eax,[esp] ; MATCH05 ULEN + base; entry to decompressor + add eax, byte ~ALIGN + UNLAP + and eax, byte ALIGN + + std + ; copy decompressor + lea esi,[-1+ ecx + esi] ; unmoved top -1 of decompressor + lea edi,[-1+ ecx + eax] ; moved top -1 of decompressor + rep + movsb + + mov ecx,[-4+ edx] ; length of compressed data + add ecx, byte 3 + and ecx, byte ~3 ; pad to 0 mod 4 + add edx,ecx ; unmoved top of compressed data + ; copy compressed data + lea esi,[-4+ edx] ; unmoved top -4 of compressed data + lea edi,[-4+ eax] ; moved top -4 of compressed data + shr ecx,2 + rep + movsd + + cld + lea esi,[4+ edi] ; &compressed [after move] + mov edi,ebp ; &uncompressed + or ebp, byte -1 ; decompressor assumption + jmp eax ; enter moved decompressor + +; ============= +; ============= CUT HERE +; ============= + +%include "header.ash" + +eof: +; __LITHEEND__ + section .data + dd -1 + dw eof + + +; vi:ts=8:et:nowrap diff --git a/src/stub/l_vmlinz.asm b/src/stub/l_vmlinz.asm index cf43c543..82399113 100644 --- a/src/stub/l_vmlinz.asm +++ b/src/stub/l_vmlinz.asm @@ -120,7 +120,7 @@ checka20: pop ecx ; MATCH05 len pop edx ; MATCH04 cto pop edi ; MATCH03 src - ckt32 0, dl + ckt32 edi, dl %endif; __LZDUMMY2__ %ifdef __LZCALLT9__ pop edi ; MATCH03 src