From de30026bbe0eed54617c22c48b9d85dee6ecbb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20Moln=C3=A1r?= Date: Wed, 13 Dec 2000 13:36:00 +0000 Subject: [PATCH] vmlinuz/i386 support. committer: ml1050 976714560 +0000 --- src/Makefile | 8 +- src/p_vmlinz.cpp | 211 ++++++++++++++++++++++++++++++++++++++++++ src/p_vmlinz.h | 77 +++++++++++++++ src/packmast.cpp | 5 +- src/stub/Makefile | 8 +- src/stub/l_vmlinz.asm | 111 ++++++++++++++++++++++ src/unupx.h | 1 + 7 files changed, 416 insertions(+), 5 deletions(-) create mode 100644 src/p_vmlinz.cpp create mode 100644 src/p_vmlinz.h create mode 100644 src/stub/l_vmlinz.asm diff --git a/src/Makefile b/src/Makefile index 5d63ff4d..02fcf38a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -59,7 +59,7 @@ OBJECTS1 = \ packer$o packhead$o packmast$o \ p_com$o p_djgpp2$o p_exe$o p_lx_elf$o p_lx_sep$o p_lx_sh$o \ p_sys$o p_tmt$o p_tos$o \ - p_unix$o p_w32pe$o p_wcle$o + p_unix$o p_w32pe$o p_wcle$o p_vmlinz$o # no exceptions or RTTI OBJECTS2 = \ @@ -164,7 +164,7 @@ DEFS += '-DUPX_CONFIG_H="config_h/linux.h"' ##CFLAGS_M += -mno-schedule-prologue CFLAGS_M += -march=i386 -mcpu=pentium CFLAGS_WERROR = -Werror -LDLIBS += -lmcheck +LDLIBS += -lmcheck -lz ifeq (1,2) # checkergcc CC = checkergcc @@ -435,7 +435,7 @@ packhead$o: packer.h packmast$o: packmast.h packer.h lefile.h \ p_com.h p_djgpp2.h p_exe.h p_lx_elf.h p_lx_sep.h p_lx_sh.h \ p_sys.h p_tmt.h p_tos.h \ - p_unix.h p_vxd.h p_w32pe.h p_wcle.h + p_unix.h p_vxd.h p_w32pe.h p_wcle.h p_vmlinz.h ui$o: packer.h ui.h work$o: packer.h ui.h packmast.h @@ -462,5 +462,7 @@ p_w32pe$o: packer.h p_w32pe.h \ stub/l_w32pe.h p_wcle$o: packer.h p_wcle.h lefile.h \ stub/l_wcle.h +p_vmlinz$o: packer.h p_vmlinz.h \ + stub/l_vmlinz.h # vi:nowrap diff --git a/src/p_vmlinz.cpp b/src/p_vmlinz.cpp new file mode 100644 index 00000000..918d567f --- /dev/null +++ b/src/p_vmlinz.cpp @@ -0,0 +1,211 @@ +/* p_vmlinz.cpp -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2000 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu + */ + + +#include "conf.h" + +#include "file.h" +#include "packer.h" +#include "p_vmlinz.h" +#include + +static const +#include "stub/l_vmlinz.h" + +const unsigned kernel_entry = 0x100000; +const unsigned stack_during_uncompression = 0x90000; + +// from /usr/src/linux/arch/i386/boot/compressed/Makefile +const unsigned bzimage_offset = 0x100000; +const unsigned zimage_offset = 0x1000; + + +PackvmlinuzI386::PackvmlinuzI386(InputFile *f) : + super(f) +{ + assert(sizeof(boot_sect_t) == 0x218); +} + + +int PackvmlinuzI386::getCompressionMethod() const +{ + if (M_IS_NRV2B(opt->method)) + return M_NRV2B_LE32; + if (M_IS_NRV2D(opt->method)) + return M_NRV2D_LE32; + return opt->level > 1 ? M_NRV2D_LE32 : M_NRV2B_LE32; +} + + +const int *PackvmlinuzI386::getFilters() const +{ + return NULL; +} + + +bool PackvmlinuzI386::canPack() +{ + boot_sect_t h; + fi->readx(&h, sizeof(h)); + if (h.boot_flag != 0xAA55) + return false; + + setup_size = (1 + (h.setup_sects ? h.setup_sects : 4)) * 0x200; + if (setup_size > file_size) + return false; + + bzImage = memcmp(h.hdrs, "HdrS", 4) == 0 && (h.load_flags & 1) != 0; + + obuf.alloc(file_size); + fi->seek(0, SEEK_SET); + fi->readx(obuf, file_size); + + ibuf.alloc(3 * 1024 * 1024); // 3M should be enough + + upx_bytep gzpos = obuf + setup_size; + while (1) + { + int pos = find(gzpos, file_size - (gzpos - obuf), "\x1F\x8B", 2); + if (pos < 0) + return false; + gzpos += pos; +#if 0 + ulen = ibuf.getSize(); + if (::uncompress(ibuf, &ulen, gzpos, file_size - (gzpos - obuf)) == Z_OK) + return true; + gzpos++; +#else + fi->seek(gzpos - obuf, SEEK_SET); + gzFile zf = gzdopen(fi->getFd(), "r"); + if (zf == 0) + return false; + ulen = gzread(zf, ibuf, ibuf.getSize()); + return ulen > (unsigned) file_size; +#endif + } + return false; +} + + +void PackvmlinuzI386::pack(OutputFile *fo) +{ + MemBuffer setupbuf(setup_size); + memcpy(setupbuf, obuf, setup_size); + + obuf.free(); + obuf.allocForCompression(ibuf.getSize()); + + // FILE *f1 = fopen("kernel.img", "wb"); fwrite(ibuf, 1, ulen, f1); fclose(f1); + + ph.u_len = ulen; + if (!compress(ibuf, obuf)) + throwNotCompressible(); + + initLoader(nrv_loader, sizeof(nrv_loader)); + + const unsigned overlapoh = bzImage ? findOverlapOverhead(obuf, 512) : 0; + unsigned clen = ph.c_len; + + if (bzImage) + { + // align everything to dword boundary - it is easier to handle + memset(obuf + clen, 0, 4); + clen = ALIGN_UP(clen, 4); + + addLoader("LINUZ000""LBZIMAGE""IDENTSTR", + "+40D++++", // align the stuff to 4 byte boundary + "UPX1HEAD", // 32 byte + "LZCUTPOI""+0000000", + getDecompressor(), + "LINUZ990", + NULL + ); + } + else + addLoader("LINUZ000""LZIMAGE0", + getDecompressor(), + "LINUZ990""IDENTSTR""UPX1HEAD", + NULL + ); + + const unsigned lsize = getLoaderSize(); + MemBuffer loader(lsize); + memcpy(loader, getLoader(), lsize); + + int e_len = bzImage ? getLoaderSection("LZCUTPOI") : lsize; + patchPackHeader(loader, lsize); + + if (bzImage) + { + assert(e_len > 0); + + const unsigned d_len4 = ALIGN_UP(lsize - e_len, 4); + const unsigned decompr_pos = ALIGN_UP(ulen + overlapoh, 16); + const unsigned copy_size = clen + d_len4; + const unsigned edi = decompr_pos + d_len4 - 4; // copy to + const unsigned esi = ALIGN_UP(clen + lsize, 4) - 4; // copy from + + unsigned jpos = find_le32(loader, e_len, get_le32("JMPD")); + patch_le32(loader, e_len, "JMPD", decompr_pos - jpos - 4); + + patch_le32(loader, e_len, "ESI1", bzimage_offset + decompr_pos - clen); + patch_le32(loader, e_len, "ECX0", copy_size / 4); + patch_le32(loader, e_len, "EDI0", bzimage_offset + edi); + patch_le32(loader, e_len, "ESI0", bzimage_offset + esi); + } + else + patch_le32(loader, lsize, "ESI1", zimage_offset + lsize); + + patch_le32(loader, e_len, "KEIP", kernel_entry); + patch_le32(loader, e_len, "STAK", stack_during_uncompression); + + ((boot_sect_t *)((unsigned char *)setupbuf))->sys_size = ALIGN_UP(lsize + clen, 16) / 16; + + fo->write(setupbuf, setupbuf.getSize()); + fo->write(loader, e_len); + fo->write(obuf, clen); + fo->write(loader + e_len, lsize - e_len); + + //if (!checkCompressionRatio(file_size, fo->getBytesWritten())) + // throwNotCompressible(); +} + +/************************************************************************* +// +**************************************************************************/ + +int PackvmlinuzI386::canUnpack() +{ + return false; +} + +void PackvmlinuzI386::unpack(OutputFile *) +{ + // no uncompression support for this format, so + // it is possible to remove the original deflate code (>10KB) + throwCantUnpack("build a new kernel instead :-)"); +} diff --git a/src/p_vmlinz.h b/src/p_vmlinz.h new file mode 100644 index 00000000..1ebb8e83 --- /dev/null +++ b/src/p_vmlinz.h @@ -0,0 +1,77 @@ +/* p_vmlinz.h -- + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996-2000 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu + */ + +/************************************************************************* +// vmlinuz/i386 (zlib compressed Linux kernel image) +**************************************************************************/ + +class PackvmlinuzI386 : public Packer +{ + typedef Packer super; +public: + PackvmlinuzI386(InputFile *f); + virtual int getVersion() const { return 1; } + virtual int getFormat() const { return UPX_F_VMLINUZ_i386; } + virtual const char *getName() const { return "vmlinuz/386"; } + virtual int getCompressionMethod() const; + virtual const int *getFilters() const; + + virtual void pack(OutputFile *fo); + virtual void unpack(OutputFile *fo); + + virtual bool canPack(); + virtual int canUnpack(); + +protected: +// virtual const upx_byte *getLoader() const; +// virtual int getLoaderSize() const; + + struct boot_sect_t + { + char _[0x1f1]; + char setup_sects; + char _1[2]; + LE16 sys_size; + char _2[8]; + LE16 boot_flag; // 0xAA55 + // 0x200 + char _3[2]; + char hdrs[4]; // "HdrS" + LE16 version; // boot protocol + char _4[9]; + char load_flags; + char _5[2]; + LE32 code32_start; + + // some more uninteresting fields here ... + // see /usr/src/linux/Documentation/i386/ + }; + + off_t setup_size; + bool bzImage; + unsigned long ulen; +}; diff --git a/src/packmast.cpp b/src/packmast.cpp index 312a49ce..8fa2ff8b 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -45,6 +45,7 @@ #include "p_tmt.h" #include "p_vxd.h" #include "p_w32pe.h" +#include "p_vmlinz.h" /************************************************************************* @@ -124,7 +125,7 @@ static Packer* try_unpack(Packer *p, InputFile *f) // FIXME - could stop testing all other unpackers at this time // see canUnpack() in packer.h } - } catch (IOException&) { + } catch (const IOException&) { } catch (...) { delete p; throw; @@ -177,6 +178,8 @@ static Packer* try_packers(InputFile *f, try_function func) if ((p = func(new PackBvmlinuxI386(f),f)) != NULL) return p; #endif + if ((p = func(new PackvmlinuzI386(f),f)) != NULL) + return p; if ((p = func(new PackLinuxI386(f),f)) != NULL) return p; if ((p = func(new PackSys(f),f)) != NULL) diff --git a/src/stub/Makefile b/src/stub/Makefile index aa15f41d..a4a55951 100644 --- a/src/stub/Makefile +++ b/src/stub/Makefile @@ -33,7 +33,8 @@ STUBS = \ l_w32pe.h \ l_lx_n2b.h l_lx_n2d.h \ l_le_n2b.h l_le_n2d.h \ - l_sh_n2b.h l_sh_n2d.h + l_sh_n2b.h l_sh_n2d.h \ + l_vmlinz.h # util var for use in the rules - basename of the current target @@ -196,6 +197,10 @@ l_w32pe.h: l_w32pe.asx $(NASM) -f bin -o $T.bin $< $(BIN2H) $T.bin nrv_loader $@ +l_vmlinz.h: l_vmlinz.asx + $(NASM) -f bin -o $T.bin $< + $(BIN2H) $T.bin nrv_loader $@ + # /*********************************************************************** # // linux rules (exec, elf, sh, sep) @@ -299,6 +304,7 @@ l_tmt.h: n2b_d32.asy n2d_d32.asy $(DEPS2) l_vxd.h: n2b_d32.asy n2d_d32.asy $(DEPS2) l_wcle.h: n2b_d32.asy n2d_d32.asy $(DEPS2) l_w32pe.h: n2b_d32.asy n2d_d32.asy $(DEPS2) +l_vmlinz.h: n2b_d32.asy n2d_d32.asy $(DEPS2) l_xe_n2b.o: n2b_d32.ash $(DEPS1) l_6e_n2b.o: n2b_d32.ash $(DEPS1) diff --git a/src/stub/l_vmlinz.asm b/src/stub/l_vmlinz.asm new file mode 100644 index 00000000..698178a7 --- /dev/null +++ b/src/stub/l_vmlinz.asm @@ -0,0 +1,111 @@ +; l_vmlinz.asm -- loader & decompressor for the vmlinuz/i386 format +; +; This file is part of the UPX executable compressor. +; +; Copyright (C) 1996-2000 Markus Franz Xaver Johannes Oberhumer +; Copyright (C) 1996-2000 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@jk.uni-linz.ac.at ml1050@cdata.tvnet.hu +; + + +%define jmps jmp short +%define jmpn jmp near +%include "macros.ash" + + BITS 32 + SECTION .text + ORG 0 + +; ============= +; ============= ENTRY POINT +; ============= + +start: +; __LINUZ000__ + cli + xor eax, eax + mov al, 0x18 + mov ds, eax + mov es, eax + mov ss, eax + mov esp, 'STAK' ; 0x90000 + + mov eax, 'KEIP' ; 0x100000 - address of startup_32 + push eax + push edi + push esi + or ebp, byte -1 + +%ifdef __LBZIMAGE__ + mov esi, 'ESI0' + mov edi, 'EDI0' + mov ecx, 'ECX0' + + std + rep + movsd + cld + + mov esi, 'ESI1' + xchg eax, edi + jmp .1 + 'JMPD' ; jump to the copied decompressor +.1: +%else; __LZIMAGE0__ + + cld + mov esi, 'ESI1' + xchg eax, edi + +; this checka20 stuff looks very unneccessary to me +checka20: + inc eax + mov [ebp + 1], eax + cmp [edi], eax + je checka20 + +%endif; __LZCUTPOI__ + +; ============= +; ============= DECOMPRESSION +; ============= + +%include "n2b_d32.ash" +%include "n2d_d32.ash" + +; ============= +; __LINUZ990__ + pop esi + pop edi + xor ebx, ebx ; booting the 1st cpu + retn + +; ============= +; ============= CUT HERE +; ============= + +%include "header.ash" + +eof: +; __LITHEEND__ + section .data + dd -1 + dw eof + diff --git a/src/unupx.h b/src/unupx.h index 40304ece..0b8e2ed3 100644 --- a/src/unupx.h +++ b/src/unupx.h @@ -80,6 +80,7 @@ typedef unsigned upx_uint32; #define UPX_F_LINUX_ELF_i386 12 #define UPX_F_LINUX_SEP_i386 13 #define UPX_F_LINUX_SH_i386 14 +#define UPX_F_VMLINUZ_i386 15 #define UPX_F_ATARI_TOS 129 #define UPX_F_SOLARIS_SPARC 130