From 51c65660929b0eb11c033bf8e8cd926bf4781865 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Tue, 27 Jun 2000 17:22:34 +0000 Subject: [PATCH] Packer::canUnpack() now can return -1. committer: mfx 962126554 +0000 --- src/except.cpp | 21 ++++++++++++++++++--- src/except.h | 5 ++++- src/file.cpp | 2 +- src/p_com.cpp | 2 +- src/p_com.h | 2 +- src/p_djgpp2.cpp | 4 ++-- src/p_djgpp2.h | 2 +- src/p_exe.cpp | 8 ++++---- src/p_exe.h | 4 ++-- src/p_lx_elf.cpp | 4 ++-- src/p_lx_elf.h | 4 ++-- src/p_tmt.cpp | 4 ++-- src/p_tmt.h | 2 +- src/p_tos.cpp | 18 +++++++++--------- src/p_tos.h | 6 +++--- src/p_unix.cpp | 6 +++--- src/p_unix.h | 4 ++-- src/p_vmlinux.cpp | 2 +- src/p_w32pe.h | 8 ++++---- src/p_wcle.cpp | 4 ++-- src/p_wcle.h | 2 +- src/packer.cpp | 26 ++++++++++++++++++++++---- src/packer.h | 17 ++++++++++++++--- src/packmast.cpp | 8 +++++++- 24 files changed, 109 insertions(+), 56 deletions(-) diff --git a/src/except.cpp b/src/except.cpp index 417a1157..9c581422 100644 --- a/src/except.cpp +++ b/src/except.cpp @@ -63,6 +63,13 @@ void throwAlreadyPacked(const char *msg) throw AlreadyPackedException(msg); } +void throwAlreadyPackedByUPX(const char *msg) +{ + if (msg == NULL) + msg = "already packed by UPX"; + throwAlreadyPacked(msg); +} + /************************************************************************* // decompression @@ -109,7 +116,15 @@ void throwBadLoader() void throwIOException(const char *msg, int e) { - throw IOException(msg,e); + throw IOException(msg, e); +} + + +void throwEOFException(const char *msg, int e) +{ + if (msg == NULL && e == 0) + msg = "premature end of file"; + throw EOFException(msg, e); } @@ -119,9 +134,9 @@ void throwIOException(const char *msg, int e) const char *prettyName(const char *n) { - while (*n >= '0' && *n <= '9') // gcc / egcs + while (*n >= '0' && *n <= '9') // gcc / egcs n++; - if (strlen(n) > 6 && memcmp(n, "class ", 6) == 0) // Visual C++ + if (strncmp(n, "class ", 6) == 0) // Visual C++ n += 6; return n; } diff --git a/src/except.h b/src/except.h index 34479b2f..80513ba7 100644 --- a/src/except.h +++ b/src/except.h @@ -192,8 +192,9 @@ public: // util **************************************************************************/ +#undef NORET #if 0 && defined(__GNUC__) -// (noreturn) is probably not the correct semantics +// (noreturn) is probably not the correct semantics for throwing exceptions #define NORET __attribute__((noreturn)) #else #define NORET @@ -203,6 +204,7 @@ void throwCantPack(const char *msg) NORET; void throwUnknownExecutableFormat(const char *msg = 0, bool warn = false) NORET; void throwNotCompressible(const char *msg = 0) NORET; void throwAlreadyPacked(const char *msg = 0) NORET; +void throwAlreadyPackedByUPX(const char *msg = 0) NORET; void throwCantUnpack(const char *msg) NORET; void throwNotPacked(const char *msg = 0) NORET; void throwFilterException() NORET; @@ -211,6 +213,7 @@ void throwChecksumError() NORET; void throwCompressedDataViolation() NORET; void throwInternalError(const char *msg) NORET; void throwIOException(const char *msg = 0, int e = 0) NORET; +void throwEOFException(const char *msg = 0, int e = 0) NORET; #undef NORET diff --git a/src/file.cpp b/src/file.cpp index 9d00eea2..d71e9e2a 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -137,7 +137,7 @@ int FileBase::readx(void *buf, int len) { int l = this->read(buf,len); if (l != len) - throw EOFException(); + throwEOFException(); return l; } diff --git a/src/p_com.cpp b/src/p_com.cpp index d09650af..3b6a8d2e 100644 --- a/src/p_com.cpp +++ b/src/p_com.cpp @@ -220,7 +220,7 @@ void PackCom::pack(OutputFile *fo) // **************************************************************************/ -bool PackCom::canUnpack() +int PackCom::canUnpack() { if (!readPackHeader(128, 0)) return false; diff --git a/src/p_com.h b/src/p_com.h index 8b3b244b..78b0c112 100644 --- a/src/p_com.h +++ b/src/p_com.h @@ -48,7 +48,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); protected: virtual const unsigned getCallTrickOffset() const { return 0x100; } diff --git a/src/p_djgpp2.cpp b/src/p_djgpp2.cpp index 4ade2505..f0727c92 100644 --- a/src/p_djgpp2.cpp +++ b/src/p_djgpp2.cpp @@ -368,13 +368,13 @@ void PackDjgpp2::pack(OutputFile *fo) // **************************************************************************/ -bool PackDjgpp2::canUnpack() +int PackDjgpp2::canUnpack() { if (!readFileHeader()) return false; if (is_dlm(fi,coff_offset)) throwCantUnpack("can't handle DLM"); - return readPackHeader(1024, coff_offset); + return readPackHeader(1024, coff_offset) ? 1 : -1; } diff --git a/src/p_djgpp2.h b/src/p_djgpp2.h index 8981cdf2..d9529132 100644 --- a/src/p_djgpp2.h +++ b/src/p_djgpp2.h @@ -49,7 +49,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); protected: virtual int buildLoader(const Filter *ft); diff --git a/src/p_exe.cpp b/src/p_exe.cpp index 5103e920..aba5ff9a 100644 --- a/src/p_exe.cpp +++ b/src/p_exe.cpp @@ -71,7 +71,7 @@ const int *PackExe::getFilters() const // **************************************************************************/ -bool PackExe::readExeHeader() +bool PackExe::readFileHeader() { ih_exesize = ih_imagesize = ih_overlay = 0; fi->readx(&ih,sizeof(ih)); @@ -95,7 +95,7 @@ bool PackExe::canPack() { if (fn_has_ext(fi->getName(),"sys")) return false; - if (!readExeHeader()) + if (!readFileHeader()) return false; if (file_size < 1024) throwCantPack("file is too small"); @@ -519,9 +519,9 @@ void PackExe::pack(OutputFile *fo) // **************************************************************************/ -bool PackExe::canUnpack() +int PackExe::canUnpack() { - if (!readExeHeader()) + if (!readFileHeader()) return false; const off_t off = ih.headsize16*16; bool b = readPackHeader(128, off); diff --git a/src/p_exe.h b/src/p_exe.h index 422d16a7..8d42de78 100644 --- a/src/p_exe.h +++ b/src/p_exe.h @@ -48,7 +48,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); // unpacker capabilities virtual bool canUnpackVersion(int version) const @@ -62,7 +62,7 @@ public: } protected: - virtual bool readExeHeader(void); + virtual bool readFileHeader(void); struct exe_header_t { diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 7d0696e9..39e840d0 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -343,7 +343,7 @@ void PackLinuxI386elf::pack(OutputFile *fo) } if ((off_t)total_in != file_size) - throw EOFException(); + throwEOFException(); // write block end marker (uncompressed size 0) fo->write("\x00\x00\x00\x00", 4); @@ -492,7 +492,7 @@ void PackLinuxI386elf::unpack(OutputFile *fo) // all bytes must be written if (total_out != orig_file_size) - throw EOFException(); + throwEOFException(); // finally test the checksums if (ph.c_adler != c_adler || ph.u_adler != u_adler) diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index c7dffc0b..53a21c7d 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -46,11 +46,11 @@ public: virtual const char *getName() const { return "linux/elf386"; } virtual const int *getFilters() const { return NULL; } - virtual bool canPack(); - virtual bool canUnpackFormat(int format) const; virtual void pack(OutputFile *fo); virtual void unpack(OutputFile *fo); + virtual bool canPack(); + virtual bool canUnpackFormat(int format) const; virtual bool canUnpackVersion(int version) const { return (version >= 11); } diff --git a/src/p_tmt.cpp b/src/p_tmt.cpp index 2e9b09fb..5cdf15ab 100644 --- a/src/p_tmt.cpp +++ b/src/p_tmt.cpp @@ -264,11 +264,11 @@ void PackTmt::pack(OutputFile *fo) } -bool PackTmt::canUnpack() +int PackTmt::canUnpack() { if (!PackTmt::readFileHeader()) return false; - return readPackHeader(512,adam_offset); + return readPackHeader(512,adam_offset) ? 1 : -1; } diff --git a/src/p_tmt.h b/src/p_tmt.h index c9bfaedf..a1c6bec2 100644 --- a/src/p_tmt.h +++ b/src/p_tmt.h @@ -48,7 +48,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); protected: bool readFileHeader(); diff --git a/src/p_tos.cpp b/src/p_tos.cpp index 8f16c1a6..a94a0aa5 100644 --- a/src/p_tos.cpp +++ b/src/p_tos.cpp @@ -126,7 +126,7 @@ int PackTos::getLoaderSize() const // util **************************************************************************/ -bool PackTos::readExeHeader() +bool PackTos::readFileHeader() { fi->seek(0,SEEK_SET); fi->readx(&ih, FH_SIZE); @@ -138,7 +138,7 @@ bool PackTos::readExeHeader() } -bool PackTos::checkExeHeader() +bool PackTos::checkFileHeader() { const unsigned f = ih.fh_flag; //printf("flags: 0x%x, text: %d, data: %d, bss: %d, sym: %d\n", f, (int)ih.fh_text, (int)ih.fh_data, (int)ih.fh_bss, (int)ih.fh_sym); @@ -235,7 +235,7 @@ static int check_relocs(const upx_byte *relocs, unsigned rsize, unsigned isize, bool PackTos::canPack() { - if (!readExeHeader()) + if (!readFileHeader()) return false; unsigned char buf[512]; @@ -243,7 +243,7 @@ bool PackTos::canPack() if (find_le32(buf,sizeof(buf),UPX_MAGIC_LE32)) throwAlreadyPacked(); - if (!checkExeHeader()) + if (!checkFileHeader()) throwCantPack("unsupported header flags"); if (file_size < 256) throwCantPack("program too small"); @@ -253,7 +253,7 @@ bool PackTos::canPack() void PackTos::fileInfo() { - if (!readExeHeader()) + if (!readFileHeader()) return; con_fprintf(stdout, " text: %d, data: %d, sym: %d, bss: %d, flags=0x%x\n", (int)ih.fh_text, (int)ih.fh_data, (int)ih.fh_sym, (int)ih.fh_bss, (int)ih.fh_flag); @@ -490,17 +490,17 @@ void PackTos::pack(OutputFile *fo) // **************************************************************************/ -bool PackTos::canUnpack() +int PackTos::canUnpack() { - if (!readPackHeader(512, 0)) + if (!readFileHeader()) return false; - if (!readExeHeader()) + if (!readPackHeader(512, 0)) return false; // check header as set by packer if ((ih.fh_text & 3) != 0 || (ih.fh_data & 3) != 0 || (ih.fh_bss & 3) != 0 || ih.fh_sym != 0 || ih.fh_reserved != 0 || ih.fh_reloc > 1) throwCantUnpack("file damaged"); - if (!checkExeHeader()) + if (!checkFileHeader()) throwCantUnpack("unsupported header flags"); return true; } diff --git a/src/p_tos.h b/src/p_tos.h index 23717df8..7a1f6416 100644 --- a/src/p_tos.h +++ b/src/p_tos.h @@ -48,7 +48,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); virtual void fileInfo(); @@ -56,8 +56,8 @@ protected: virtual const upx_byte *getLoader() const; virtual int getLoaderSize() const; - bool readExeHeader(); - bool checkExeHeader(); + bool readFileHeader(); + bool checkFileHeader(); struct tos_header_t { diff --git a/src/p_unix.cpp b/src/p_unix.cpp index 4ba22b4e..eac09cd8 100644 --- a/src/p_unix.cpp +++ b/src/p_unix.cpp @@ -172,7 +172,7 @@ void PackUnix::pack(OutputFile *fo) total_out += ph.c_len; } if ((off_t)total_in != file_size) - throw EOFException(); + throwEOFException(); // write block end marker (uncompressed size 0) fo->write("\x00\x00\x00\x00", 4); @@ -203,7 +203,7 @@ void PackUnix::pack(OutputFile *fo) // Generic Unix canUnpack(). **************************************************************************/ -bool PackUnix::canUnpack() +int PackUnix::canUnpack() { upx_byte buf[128]; const int bufsize = sizeof(buf); @@ -310,7 +310,7 @@ void PackUnix::unpack(OutputFile *fo) // all bytes must be written if (ph.version > 8 && total_out != orig_file_size) - throw EOFException(); + throwEOFException(); // finally test the checksums if (ph.c_adler != c_adler || ph.u_adler != u_adler) diff --git a/src/p_unix.h b/src/p_unix.h index 9e8f9730..b3508229 100644 --- a/src/p_unix.h +++ b/src/p_unix.h @@ -47,7 +47,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); protected: // called by the generic pack() @@ -175,7 +175,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); protected: // virtual const upx_byte *getLoader() const; diff --git a/src/p_vmlinux.cpp b/src/p_vmlinux.cpp index dba065f3..0cee4881 100644 --- a/src/p_vmlinux.cpp +++ b/src/p_vmlinux.cpp @@ -137,7 +137,7 @@ void PackBvmlinuxI386::pack(OutputFile *fo) // **************************************************************************/ -bool PackBvmlinuxI386::canUnpack() +int PackBvmlinuxI386::canUnpack() { return false; } diff --git a/src/p_w32pe.h b/src/p_w32pe.h index 10f48c63..4a5b930d 100644 --- a/src/p_w32pe.h +++ b/src/p_w32pe.h @@ -56,15 +56,15 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); // unpacker capabilities virtual bool canUnpackVersion(int version) const - { - return (version == 12); - } + { return (version == 12); } protected: + virtual bool testUnpackVersion(int version) const; + unsigned pe_offset; bool isrtm; bool readFileHeader(); diff --git a/src/p_wcle.cpp b/src/p_wcle.cpp index c50a38ae..746745c7 100644 --- a/src/p_wcle.cpp +++ b/src/p_wcle.cpp @@ -740,12 +740,12 @@ void PackWcle::decodeEntryTable() } -bool PackWcle::canUnpack() +int PackWcle::canUnpack() { if (!LeFile::readFileHeader()) return false; // FIXME: 1024 could be too large for some files - return super::readPackHeader(1024, ih.data_pages_offset+exe_offset); + return readPackHeader(1024, ih.data_pages_offset+exe_offset) ? 1 : -1; } diff --git a/src/p_wcle.h b/src/p_wcle.h index 342b8e8d..5e473733 100644 --- a/src/p_wcle.h +++ b/src/p_wcle.h @@ -48,7 +48,7 @@ public: virtual void unpack(OutputFile *fo); virtual bool canPack(); - virtual bool canUnpack(); + virtual int canUnpack(); protected: virtual void handleStub(OutputFile *fo); diff --git a/src/packer.cpp b/src/packer.cpp index f2bd9590..fdb7e46a 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -39,7 +39,7 @@ **************************************************************************/ Packer::Packer(InputFile *f) : - fi(f), file_size(-1), + fi(f), file_size(-1), ph_format(-1), ph_version(-1), uip(NULL), pass(0), total_passes(0), linker(NULL), last_patch(NULL), last_patch_offset(0) { @@ -119,6 +119,24 @@ void Packer::fileInfo() } +bool Packer::testUnpackVersion(int version) const +{ + if (version != ph_version && ph_version != -1) + throwCantUnpack("program has been modified; run a virus checker!"); + if (!canUnpackVersion(version)) + throwCantUnpack("I am not compatible with older versions of UPX"); + return true; +} + + +bool Packer::testUnpackFormat(int format) const +{ + if (format != ph_format && ph_format != -1) + throwCantUnpack("program has been modified; run a virus checker!"); + return canUnpackFormat(format); +} + + /************************************************************************* // compress **************************************************************************/ @@ -575,8 +593,8 @@ bool Packer::readPackHeader(unsigned len, off_t seek_offset, upx_byte *buf) // Some formats might be able to unpack old versions because // their implementation hasn't changed. Ask them. if (opt->cmd != CMD_FILEINFO) - if (!canUnpackVersion(ph.version)) - throwCantUnpack("I am not compatible with older versions of UPX"); + if (!testUnpackVersion(ph.version)) + return false; if (ph.c_len >= ph.u_len || (off_t)ph.c_len >= file_size || ph.version <= 0 || ph.version >= 0xff) @@ -596,7 +614,7 @@ bool Packer::readPackHeader(unsigned len, off_t seek_offset, upx_byte *buf) throwCantUnpack("unknown compression method"); // Some formats might be able to unpack "subformats". Ask them. - if (!canUnpackFormat(ph.format)) + if (!testUnpackFormat(ph.format)) return false; return true; diff --git a/src/packer.h b/src/packer.h index ebe71204..0e970e4c 100644 --- a/src/packer.h +++ b/src/packer.h @@ -119,6 +119,11 @@ public: virtual bool canUnpackFormat(int format) const { return (format == getFormat()); } +protected: + // unpacker tests - these may throw exceptions + virtual bool testUnpackVersion(int version) const; + virtual bool testUnpackFormat(int format) const; + protected: virtual void pack(OutputFile *fo) = 0; virtual void unpack(OutputFile *fo) = 0; @@ -127,10 +132,14 @@ protected: virtual void fileInfo(); public: + // canPack() should throw a cantPackException eplaining why it + // cannot pack a recognized format. + // canUnpack() can return -1 meaning "format recognized, but file + // is definitely not packed" (see packmast.cpp). virtual bool canPack() = 0; - virtual bool canUnpack() = 0; - virtual bool canTest() { return canUnpack(); } - virtual bool canList() { return canUnpack(); } + virtual int canUnpack() = 0; + virtual int canTest() { return canUnpack(); } + virtual int canList() { return canUnpack(); } protected: // main compression drivers @@ -215,6 +224,8 @@ protected: InputFile *fi; off_t file_size; // will get set by constructor PackHeader ph; // must be filled by canUnpack() + int ph_format; + int ph_version; // compression buffers MemBuffer ibuf; // input diff --git a/src/packmast.cpp b/src/packmast.cpp index 765a80bc..27fa7736 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -112,11 +112,17 @@ static Packer* try_unpack(Packer *p, InputFile *f) try { p->initPackHeader(); f->seek(0,SEEK_SET); - if (p->canUnpack()) + int r = p->canUnpack(); + if (r > 0) { f->seek(0,SEEK_SET); return p; } + if (r < 0) + { + // FIXME - could stop testing all other unpackers at this time + // see canUnpack() in packer.h + } } catch (IOException&) { } catch (...) { delete p;