📄 p_unix.cpp
字号:
/* p_unix.cpp -- This file is part of the UPX executable compressor. 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 */#include "conf.h"#include "file.h"#include "filter.h"#include "packer.h"#include "p_unix.h"#include "p_elf.h"// do not change#define BLOCKSIZE (512*1024)/*************************************************************************//**************************************************************************/PackUnix::PackUnix(InputFile *f) : super(f), exetype(0), blocksize(0), overlay_offset(0), lsize(0){ 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);}// common part of canPack(), enhanced by subclassesbool PackUnix::canPack(){ if (exetype == 0) return false;#if defined(__unix__) // must be executable by owner if ((fi->st.st_mode & S_IXUSR) == 0) throwCantPack("file not executable; try 'chmod +x'");#endif if (file_size < 4096) throwCantPack("file is too small"); // info: currently the header is 36 (32+4) bytes before EOF unsigned char buf[256]; fi->seek(-(off_t)sizeof(buf), SEEK_END); fi->readx(buf, sizeof(buf)); checkAlreadyPacked(buf, sizeof(buf)); return true;}void PackUnix::writePackHeader(OutputFile *fo){ unsigned char buf[32]; memset(buf, 0, sizeof(buf)); const int hsize = ph.getPackHeaderSize(); assert((unsigned)hsize <= sizeof(buf)); // note: magic constants are always le32 set_le32(buf+0, UPX_MAGIC_LE32); set_le32(buf+4, UPX_MAGIC2_LE32); checkPatch(NULL, 0, 0, 0); // reset patchPackHeader(buf, hsize); checkPatch(NULL, 0, 0, 0); // reset fo->write(buf, hsize);}/*************************************************************************// Generic Unix pack(). Subclasses must provide patchLoader().//// A typical compressed Unix executable looks like this:// - loader stub// - 12 bytes header info// - the compressed blocks, each with a 8 byte header for block sizes// - 4 bytes block end marker (uncompressed size 0)// - 32 bytes UPX packheader// - 4 bytes overlay offset (needed for decompression)**************************************************************************/// see note below and Packer::compress()bool PackUnix::checkCompressionRatio(unsigned, unsigned) const{ return true;}void PackUnix::pack1(OutputFile * /*fo*/, Filter & /*ft*/){ // derived class usually provides this}int PackUnix::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==filter_strategy). // Else try the first two filters, and pick the better (2==filter_strategy). return (opt->no_filter ? -3 : ((opt->filter > 0) ? -2 : 2));}void PackUnix::pack2(OutputFile *fo, Filter &ft){ // compress blocks unsigned total_in = 0; unsigned total_out = 0;// FIXME: ui_total_passes is not correct with multiple blocks...// ui_total_passes = (file_size + blocksize - 1) / blocksize;// if (ui_total_passes == 1)// ui_total_passes = 0; unsigned remaining = file_size; while (remaining > 0) { // FIXME: disable filters if we have more than one block. // FIXME: There is only 1 un-filter in the stub [as of 2002-11-10]. // So the next block really has no choice! // This merely prevents an assert() in compressWithFilters(), // which assumes it has free choice on each call [block]. // And if the choices aren't the same on each block, // then un-filtering will give incorrect results. int filter_strategy = getStrategy(ft); if (file_size > (off_t)blocksize) filter_strategy = -3; // no filters int l = fi->readx(ibuf, UPX_MIN(blocksize, remaining)); remaining -= l; // Note: compression for a block can fail if the // file is e.g. blocksize + 1 bytes long // compress ph.overlap_overhead = 0; ph.c_len = ph.u_len = l; ft.buf_len = l; // compressWithFilters() updates u_adler _inside_ compress(); // that is, AFTER filtering. We want BEFORE filtering, // so that decompression checks the end-to-end checksum. unsigned const end_u_adler = upx_adler32(ibuf, ph.u_len, ph.u_adler); compressWithFilters(&ft, OVERHEAD, NULL_cconf, filter_strategy); if (ph.c_len < ph.u_len) { const upx_bytep tbuf = NULL; if (ft.id == 0) tbuf = ibuf; ph.overlap_overhead = OVERHEAD; if (!testOverlappingDecompression(obuf, tbuf, 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 manually update checksum of compressed data ph.c_adler = upx_adler32(ibuf, ph.u_len, ph.saved_c_adler); } // write block header b_info blk_info; memset(&blk_info, 0, sizeof(blk_info)); set_native32(&blk_info.sz_unc, ph.u_len); set_native32(&blk_info.sz_cpr, ph.c_len); if (ph.c_len < ph.u_len) { blk_info.b_method = (unsigned char) ph.method; blk_info.b_ftid = (unsigned char) ph.filter; blk_info.b_cto8 = (unsigned char) ph.filter_cto; } fo->write(&blk_info, sizeof(blk_info)); b_len += sizeof(b_info); // write compressed data if (ph.c_len < ph.u_len) { fo->write(obuf, ph.c_len); verifyOverlappingDecompression(); // uses ph.u_adler } else { fo->write(ibuf, ph.u_len); } ph.u_adler = end_u_adler; total_in += ph.u_len; total_out += ph.c_len; } // update header with totals ph.u_len = total_in; ph.c_len = total_out; if ((off_t)total_in != file_size) { throwEOFException(); }}voidPackUnix::patchLoaderChecksum(){ unsigned char *const ptr = 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 *p = getLoader(); lsize = getLoaderSize(); updateLoader(fo); patchLoaderChecksum(); fo->write(p, lsize);}void PackUnix::pack4(OutputFile *fo, Filter &){ writePackHeader(fo); unsigned tmp; set_native32(&tmp, overlay_offset); fo->write(&tmp, sizeof(tmp));}void PackUnix::pack(OutputFile *fo){ Filter ft(ph.level); ft.addvalue = 0; b_len = 0; progid = 0; // set options blocksize = opt->o_unix.blocksize; if (blocksize <= 0) blocksize = BLOCKSIZE; if ((off_t)blocksize > file_size) blocksize = file_size; // init compression buffers ibuf.alloc(blocksize); obuf.allocForCompression(blocksize); fi->seek(0, SEEK_SET); pack1(fo, ft); // generate Elf header, etc. p_info hbuf; set_native32(&hbuf.p_progid, progid); set_native32(&hbuf.p_filesize, file_size); set_native32(&hbuf.p_blocksize, blocksize); fo->write(&hbuf, sizeof(hbuf)); pack2(fo, ft); // append the compressed body // write block end marker (uncompressed size 0) b_info hdr; memset(&hdr, 0, sizeof(hdr)); set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32); fo->write(&hdr, sizeof(hdr)); pack3(fo, ft); // append loader pack4(fo, ft); // append PackHeader and overlay_offset; update Elf header // finally check the compression ratio if (!checkFinalCompressionRatio(fo)) throwNotCompressible();}void PackUnix::packExtent( const Extent &x, unsigned &total_in, unsigned &total_out, Filter *ft, OutputFile *fo, unsigned hdr_u_len){ unsigned const init_u_adler = ph.u_adler; unsigned const init_c_adler = ph.c_adler; MemBuffer hdr_ibuf; if (hdr_u_len) { hdr_ibuf.alloc(hdr_u_len); fi->seek(0, SEEK_SET); int l = fi->readx(hdr_ibuf, hdr_u_len); (void)l; } fi->seek(x.offset, SEEK_SET); for (off_t rest = x.size; 0 != rest; ) { int const filter_strategy = getStrategy(*ft);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -