📄 packer.cpp
字号:
/*************************************************************************// overlapping decompression**************************************************************************/bool ph_testOverlappingDecompression(const PackHeader &ph, const upx_bytep buf, const upx_bytep tbuf, unsigned overlap_overhead){ if (ph.c_len >= ph.u_len) return false; assert((int) overlap_overhead >= 0); assert((int) (ph.u_len + overlap_overhead) >= 0); // Because upx_test_overlap() does not use the asm_fast decompressor // we must account for extra 3 bytes that asm_fast does use, // or else we may fail at runtime decompression. unsigned extra = 0; if (M_IS_NRV2B(ph.method) || M_IS_NRV2D(ph.method) || M_IS_NRV2E(ph.method)) extra = 3; if (overlap_overhead <= 4 + extra) // don't waste time here return false; overlap_overhead -= extra; unsigned src_off = ph.u_len + overlap_overhead - ph.c_len; unsigned new_len = ph.u_len; int r = upx_test_overlap(buf - src_off, tbuf, src_off, ph.c_len, &new_len, ph.method, &ph.compress_result); if (r == UPX_E_OUT_OF_MEMORY) throwOutOfMemoryException(); return (r == UPX_E_OK && new_len == ph.u_len);}bool Packer::testOverlappingDecompression(const upx_bytep buf, const upx_bytep tbuf, unsigned overlap_overhead) const{ return ph_testOverlappingDecompression(ph, buf, tbuf, overlap_overhead);}void Packer::verifyOverlappingDecompression(Filter *ft){ assert(ph.c_len < ph.u_len); assert((int)ph.overlap_overhead > 0); // Idea: // obuf[] was allocated with MemBuffer::allocForCompression(), and // its contents are no longer needed, i.e. the compressed data // must have been already written. // We now can perform a real overlapping decompression and // verify the checksum. // // Note: // This verify is just because of complete paranoia that there // could be a hidden bug in the upx_test_overlap implementation, // and it should not be necessary at all. // // See also: // Filter::verifyUnfilter() if (ph_skipVerify(ph)) return; unsigned offset = (ph.u_len + ph.overlap_overhead) - ph.c_len; if (offset + ph.c_len > obuf.getSize()) return; memmove(obuf + offset, obuf, ph.c_len); decompress(obuf + offset, obuf, true, ft); obuf.checkState();}void Packer::verifyOverlappingDecompression(upx_bytep o_ptr, unsigned o_size, Filter *ft){ assert(ph.c_len < ph.u_len); assert((int)ph.overlap_overhead > 0); if (ph_skipVerify(ph)) return; unsigned offset = (ph.u_len + ph.overlap_overhead) - ph.c_len; if (offset + ph.c_len > o_size) return; memmove(o_ptr + offset, o_ptr, ph.c_len); decompress(o_ptr + offset, o_ptr, true, ft);}/*************************************************************************// Find overhead for in-place decompression in an heuristic way// (using a binary search). Return 0 on error.//// To speed up things:// - you can pass the range of an acceptable interval (so that// we can succeed early)// - you can enforce an upper_limit (so that we can fail early)**************************************************************************/unsigned Packer::findOverlapOverhead(const upx_bytep buf, const upx_bytep tbuf, unsigned range, unsigned upper_limit) const{ assert((int) range >= 0); // prepare to deal with very pessimistic values unsigned low = 1; unsigned high = UPX_MIN(ph.u_len + 512, upper_limit); // but be optimistic for first try (speedup) unsigned m = UPX_MIN(16u, high); // unsigned overhead = 0; unsigned nr = 0; // statistics while (high >= low) { assert(m >= low); assert(m <= high); assert(m < overhead || overhead == 0); nr++; bool success = testOverlappingDecompression(buf, tbuf, m); //printf("testOverlapOverhead(%d): %d %d: %d -> %d\n", nr, low, high, m, (int)success); if (success) { overhead = m; // Succeed early if m lies in [low .. low+range-1], i.e. if // if the range of the current interval is <= range. // if (m <= low + range - 1) // if (m < low + range) if (m - low < range) // avoid underflow break; high = m - 1; } else low = m + 1; ////m = (low + high) / 2; m = (low & high) + ((low ^ high) >> 1); // avoid overflow } //printf("findOverlapOverhead: %d (%d tries)\n", overhead, nr); if (overhead == 0) throwInternalError("this is an oo bug"); UNUSED(nr); return overhead;}/*************************************************************************// file i/o utils**************************************************************************/void Packer::handleStub(InputFile *fif, OutputFile *fo, long size){ if (fo) { if (size > 0) { // copy stub from exe info("Copying original stub: %ld bytes", size); ByteArray(stub, size); fif->seek(0,SEEK_SET); fif->readx(stub,size); fo->write(stub,size); } else { // no stub } }}void Packer::checkOverlay(unsigned overlay){ if ((int)overlay < 0 || (off_t)overlay > file_size) throw OverlayException("invalid overlay size; file is possibly corrupt"); if (overlay == 0) return; info("Found overlay: %d bytes", overlay); if (opt->overlay == opt->SKIP_OVERLAY) throw OverlayException("file has overlay -- skipped; try '--overlay=copy'");}void Packer::copyOverlay(OutputFile *fo, unsigned overlay, MemBuffer *buf, bool do_seek){ assert((int)overlay >= 0); assert((off_t)overlay < file_size); buf->checkState(); if (!fo || overlay == 0) return; if (opt->overlay != opt->COPY_OVERLAY) { assert(opt->overlay == opt->STRIP_OVERLAY); infoWarning("stripping overlay: %d bytes", overlay); return; } info("Copying overlay: %d bytes", overlay); if (do_seek) fi->seek(-(off_t)overlay, SEEK_END); // get buffer size, align to improve i/o speed unsigned buf_size = buf->getSize(); if (buf_size > 65536) buf_size = ALIGN_DOWN(buf_size, 4096u); assert((int)buf_size > 0); do { unsigned len = overlay < buf_size ? overlay : buf_size; fi->readx(buf, len); fo->write(buf, len); overlay -= len; } while (overlay > 0); buf->checkState();}// Create a pseudo-unique program id.unsigned Packer::getRandomId() const{ if (opt->debug.disable_random_id) return 0x01020304; unsigned id = 0;#if 0 && defined(__unix__) // Don't consume precious bytes from /dev/urandom. int fd = open("/dev/urandom", O_RDONLY); if (fd < 0) fd = open("/dev/random", O_RDONLY); if (fd >= 0) { if (read(fd, &id, 4) != 4) id = 0; close(fd); }#endif while (id == 0) {#if !defined(HAVE_GETTIMEOFDAY) || defined(__DJGPP__) id ^= (unsigned) time(NULL); id ^= ((unsigned) clock()) << 12;#else struct timeval tv; gettimeofday(&tv, 0); id ^= (unsigned) tv.tv_sec; id ^= ((unsigned) tv.tv_usec) << 12; // shift into high-bits#endif#if defined(HAVE_GETPID) id ^= (unsigned) getpid();#endif id ^= (unsigned) fi->st.st_ino; id ^= (unsigned) fi->st.st_atime; id ^= (unsigned) rand(); } return id;}/*************************************************************************// packheader util**************************************************************************/// this is called directly after the constructor from class PackMastervoid Packer::initPackHeader(){ memset(&ph, 0, sizeof(ph)); ph.version = getVersion(); ph.format = getFormat(); ph.method = M_NONE; ph.level = -1; ph.u_adler = ph.c_adler = ph.saved_u_adler = ph.saved_c_adler = upx_adler32(NULL,0); ph.buf_offset = -1; ph.u_file_size = file_size;}// this is called directly after canPack() from class PackMastervoid Packer::updatePackHeader(){ assert(opt->cmd == CMD_COMPRESS); // const int *m = getCompressionMethods(opt->method, opt->level); ph.method = m[0]; ph.level = opt->level; if (ph.level < 0) ph.level = file_size < 512*1024 ? 8 : 7; // assert(isValidCompressionMethod(ph.method)); assert(1 <= ph.level && ph.level <= 10);}// FIXME: remove patchPackHeader() and fold into relocateLoader();// then make linker->relocate() private (friend Packer)int Packer::patchPackHeader(void *b, int blen){ assert(isValidFilter(ph.filter)); const int size = ph.getPackHeaderSize(); if (linker->findSection("UPX1HEAD", false)) assert(size == linker->getSectionSize("UPX1HEAD")); int boff = find_le32(b, blen, UPX_MAGIC_LE32); checkPatch(b, blen, boff, size); unsigned char *p = (unsigned char *)b + boff; ph.putPackHeader(p); return boff;}bool Packer::getPackHeader(void *b, int blen, bool allow_incompressible){ if (!ph.fillPackHeader((unsigned char *)b, blen)) return false; if (ph.version > getVersion()) throwCantUnpack("need a newer version of UPX"); // Some formats might be able to unpack old versions because // their implementation hasn't changed. Ask them. if (opt->cmd != CMD_FILEINFO) if (!testUnpackVersion(ph.version)) return false; if (ph.c_len > ph.u_len || (ph.c_len == ph.u_len && !allow_incompressible) || (off_t)ph.c_len >= file_size || ph.version <= 0 || ph.version >= 0xff) throwCantUnpack("header corrupted"); else if ((off_t)ph.u_len > ph.u_file_size) {#if 0 // FIXME: does this check make sense w.r.t. overlays ??? if (ph.format == UPX_F_W32_PE || ph.format == UPX_F_DOS_EXE) // may get longer ((void)0); else throwCantUnpack("header size corrupted");#endif } if (!isValidCompressionMethod(ph.method)) throwCantUnpack("unknown compression method (try a newer version of UPX)"); // Some formats might be able to unpack "subformats". Ask them. if (!testUnpackFormat(ph.format)) return false; return true;}bool Packer::readPackHeader(int len, bool allow_incompressible){ assert((int)len > 0); MemBuffer buf(len); len = fi->read(buf, len); if (len <= 0) return false; return getPackHeader(buf, len, allow_incompressible);}void Packer::checkAlreadyPacked(const void *b, int blen){ int boff = find_le32(b, blen, UPX_MAGIC_LE32); if (boff < 0) return; // FIXME: could add some more checks to verify that this // is a real PackHeader, e.g. // //PackHeader tmp; //if (!tmp.fillPackHeader((unsigned char *)b + boff, blen - boff)) // return; // // This also would require that the buffer in 'b' holds // the full PackHeader, and not only the 4 magic bytes. throwAlreadyPacked();}/*************************************************************************// patch util for loader**************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -