int PackUnix::canUnpack() { int const small = 32 + sizeof(overlay_offset); // Allow zero-filled last page, for Mac OS X code signing. int bufsize = 2*4096 + 2*small +1; if (bufsize > fi->st_size()) bufsize = fi->st_size(); MemBuffer buf(bufsize); fi->seek(-(off_t)bufsize, SEEK_END); fi->readx(buf, bufsize); int i = bufsize; while (i > small && 0 == buf[--i]) { } i -= small; // allow incompressible extents if (i < 0 || !getPackHeader(buf + i, bufsize - i, true)) return false; int l = ph.buf_offset + ph.getPackHeaderSize(); if (l < 0 || l + 4 > bufsize) throwCantUnpack("file corrupted"); overlay_offset = get_te32(buf + i + l); if ((off_t)overlay_offset >= file_size) throwCantUnpack("file corrupted"); return true; }
int PackTos::canUnpack() { if (!readFileHeader()) return false; if (!readPackHeader(768)) 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("program header damaged"); // generic check if (!checkFileHeader()) throwCantUnpack("unsupported header flags"); return true; }
int PackHeader::getPackHeaderSize() const { if (format < 0 || version < 0) throwInternalError("getPackHeaderSize"); int n = 0; if (version <= 3) n = 24; else if (version <= 9) { if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS) n = 20; else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH) n = 25; else n = 28; } else { if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS) n = 22; else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH) n = 27; else n = 32; } if (n < 20) throwCantUnpack("unknown header version"); return n; }
void PackCom::unpack(OutputFile *fo) { ibuf.alloc(file_size); obuf.allocForUncompression(ph.u_len); // read whole file fi->seek(0,SEEK_SET); fi->readx(ibuf,file_size); // get compressed data offset int e_len = ph.buf_offset + ph.getPackHeaderSize(); if (file_size <= e_len + (off_t)ph.c_len) throwCantUnpack("file damaged"); // decompress decompress(ibuf+e_len,obuf); // unfilter Filter ft(ph.level); ft.init(ph.filter, getCallTrickOffset()); ft.unfilter(obuf,ph.u_len); // write decompressed file if (fo) fo->write(obuf,ph.u_len); }
void PackVmlinuzI386::unpack(OutputFile *fo) { // no uncompression support for this format, so that // it is possible to remove the original deflate code (>10 KiB) // FIXME: but we could write the uncompressed "vmlinux" image ibuf.alloc(ph.c_len); obuf.allocForUncompression(ph.u_len); fi->seek(setup_size + ph.buf_offset + ph.getPackHeaderSize(), SEEK_SET); fi->readx(ibuf, ph.c_len); // decompress decompress(ibuf, obuf); // unfilter Filter ft(ph.level); ft.init(ph.filter, physical_start); ft.cto = (unsigned char) ph.filter_cto; ft.unfilter(obuf, ph.u_len); // write decompressed file if (fo) { throwCantUnpack("build a new kernel instead :-)"); //fo->write(obuf, ph.u_len); } }
int PackUnix::canUnpack() { upx_byte buf[sizeof(overlay_offset) + 32]; const int bufsize = sizeof(buf); fi->seek(-bufsize, SEEK_END); fi->readx(buf, bufsize); if (!getPackHeader(buf, bufsize, true)) // allow incompressible extents return false; int l = ph.buf_offset + ph.getPackHeaderSize(); if (l < 0 || l + 4 > bufsize) throwCantUnpack("file corrupted"); overlay_offset = get_te32(buf+l); if ((off_t)overlay_offset >= file_size) throwCantUnpack("file corrupted"); return true; }
static const #include "stub/arm.v4a-wince.pe.h" static const #include "stub/arm.v4t-wince.pe.h" #define IDSIZE(x) ih.ddirs[x].size #define IDADDR(x) ih.ddirs[x].vaddr #define ODSIZE(x) oh.ddirs[x].size #define ODADDR(x) oh.ddirs[x].vaddr #define isdll ((ih.flags & DLL_FLAG) != 0) #define FILLVAL 0 /************************************************************************* // **************************************************************************/ #if defined(__BORLANDC__) # undef strcpy # define strcpy(a,b) strcpy((char *)(a),(const char *)(b)) #endif #if (__ACC_CXX_HAVE_PLACEMENT_DELETE) || defined(__DJGPP__) #include "bptr.h" #define IPTR(type, var) BoundedPtr<type> var(ibuf, ibuf.getSize()) #define OPTR(type, var) BoundedPtr<type> var(obuf, obuf.getSize()) #define IPTR_I(type, var, v) BoundedPtr<type> var(ibuf, ibuf.getSize(), v) #define OPTR_I(type, var, v) BoundedPtr<type> var(obuf, obuf.getSize(), v) #define IPTR_C(type, var, v) const BoundedPtr<type> var(ibuf, ibuf.getSize(), v) #define OPTR_C(type, var, v) const BoundedPtr<type> var(obuf, obuf.getSize(), v) #else #define IPTR(type, var) type* var = 0 #define OPTR(type, var) type* var = 0 #define IPTR_I(type, var, v) type* var = (v) #define OPTR_I(type, var, v) type* var = (v) #define IPTR_C(type, var, v) type* const var = (v) #define OPTR_C(type, var, v) type* const var = (v) #endif static void xcheck(const void *p, size_t plen, const void *b, size_t blen) { const char *pp = (const char *) p; const char *bb = (const char *) b; if (pp < bb || pp > bb + blen || pp + plen > bb + blen) throwCantUnpack("pointer out of range; take care!"); }
bool PackHeader::fillPackHeader(const upx_bytep buf, int blen) { int boff = find_le32(buf, blen, UPX_MAGIC_LE32); if (boff < 0) return false; if (boff + 8 <= 0 || boff + 8 > blen) throwCantUnpack("header corrupted 1"); const upx_bytep p = buf + boff; version = p[4]; format = p[5]; method = p[6]; level = p[7]; filter_cto = 0; const int size = getPackHeaderSize(); if (boff + size <= 0 || boff + size > blen) throwCantUnpack("header corrupted 2"); // // decode the new variable length header // int off_filter = 0; if (format < 128) { u_adler = get_le32(p+8); c_adler = get_le32(p+12); if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS) { u_len = get_le16(p+16); c_len = get_le16(p+18); u_file_size = u_len; off_filter = 20; } else if (format == UPX_F_DOS_EXE || format == UPX_F_DOS_EXEH) { u_len = get_le24(p+16); c_len = get_le24(p+19); u_file_size = get_le24(p+22); off_filter = 25; } else { u_len = get_le32(p+16); c_len = get_le32(p+20); u_file_size = get_le32(p+24); off_filter = 28; filter_cto = p[29]; n_mru = p[30] ? 1 + p[30] : 0; } } else { u_len = get_be32(p+8); c_len = get_be32(p+12); u_adler = get_be32(p+16); c_adler = get_be32(p+20); u_file_size = get_be32(p+24); off_filter = 28; filter_cto = p[29]; n_mru = p[30] ? 1 + p[30] : 0; } if (version >= 10) filter = p[off_filter]; else if ((level & 128) == 0) filter = 0; else { // convert old flags to new filter id level &= 127; if (format == UPX_F_DOS_COM || format == UPX_F_DOS_SYS) filter = 0x06; else filter = 0x26; } level &= 15; // // now some checks // if (version == 0xff) throwCantUnpack("cannot unpack UPX ;-)"); // check header_checksum if (version > 9) if (p[size - 1] != get_packheader_checksum(p, size - 1)) throwCantUnpack("header corrupted 3"); // // success // this->buf_offset = boff; return true; }
void PackLinuxElf32x86interp::unpack(OutputFile *fo) { #define MAX_INTERP_HDR 512 union { unsigned char buf[MAX_INTERP_HDR]; //struct { Elf32_Ehdr ehdr; Elf32_Phdr phdr; } e; } u; Elf32_Ehdr *const ehdr = (Elf32_Ehdr *) u.buf; Elf32_Phdr const *phdr = (Elf32_Phdr *) (u.buf + sizeof(*ehdr)); unsigned szb_info = sizeof(b_info); { fi->seek(0, SEEK_SET); fi->readx(u.buf, MAX_INTERP_HDR); unsigned const e_entry = get_te32(&ehdr->e_entry); if (e_entry < 0x401180) { /* old style, 8-byte b_info */ szb_info = 2*sizeof(unsigned); } } fi->seek(overlay_offset, SEEK_SET); p_info hbuf; fi->readx(&hbuf, sizeof(hbuf)); unsigned orig_file_size = get_te32(&hbuf.p_filesize); blocksize = get_te32(&hbuf.p_blocksize); if (file_size > (off_t)orig_file_size || blocksize > orig_file_size) throwCantUnpack("file header corrupted"); ibuf.alloc(blocksize + OVERHEAD); b_info bhdr; memset(&bhdr, 0, sizeof(bhdr)); fi->readx(&bhdr, szb_info); ph.u_len = get_te32(&bhdr.sz_unc); ph.c_len = get_te32(&bhdr.sz_cpr); ph.filter_cto = bhdr.b_cto8; // Uncompress Ehdr and Phdrs. fi->readx(ibuf, ph.c_len); decompress(ibuf, (upx_byte *)ehdr, false); unsigned total_in = 0; unsigned total_out = 0; unsigned c_adler = upx_adler32(NULL, 0); unsigned u_adler = upx_adler32(NULL, 0); off_t ptload0hi=0, ptload1lo=0, ptload1sz=0; // decompress PT_LOAD bool first_PF_X = true; fi->seek(- (off_t) (szb_info + ph.c_len), SEEK_CUR); for (unsigned j=0; j < ehdr->e_phnum; ++phdr, ++j) { if (PT_LOAD==phdr->p_type) { if (0==ptload0hi) { ptload0hi = phdr->p_filesz + phdr->p_offset; } else if (0==ptload1lo) { ptload1lo = phdr->p_offset; ptload1sz = phdr->p_filesz; } if (fo) fo->seek(phdr->p_offset, SEEK_SET); if (Elf32_Phdr::PF_X & phdr->p_flags) { unpackExtent(phdr->p_filesz, fo, total_in, total_out, c_adler, u_adler, first_PF_X, szb_info); first_PF_X = false; } else { unpackExtent(phdr->p_filesz, fo, total_in, total_out, c_adler, u_adler, false, szb_info); } } } if (0!=ptload1sz && ptload0hi < ptload1lo) { // alignment hole? if (fo) fo->seek(ptload0hi, SEEK_SET); unpackExtent(ptload1lo - ptload0hi, fo, total_in, total_out, c_adler, u_adler, false, szb_info); } if (total_out != orig_file_size) { // non-PT_LOAD stuff if (fo) fo->seek(0, SEEK_END); unpackExtent(orig_file_size - total_out, fo, total_in, total_out, c_adler, u_adler, false, szb_info); } // check for end-of-file fi->readx(&bhdr, szb_info); unsigned const sz_unc = ph.u_len = get_te32(&bhdr.sz_unc); if (sz_unc == 0) { // uncompressed size 0 -> EOF // note: magic is always stored le32 unsigned const sz_cpr = get_le32(&bhdr.sz_cpr); if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic throwCompressedDataViolation(); } else { // extra bytes after end? throwCompressedDataViolation(); } // update header with totals ph.c_len = total_in; ph.u_len = total_out; // all bytes must be written if (total_out != orig_file_size) throwEOFException(); // finally test the checksums if (ph.c_adler != c_adler || ph.u_adler != u_adler) throwChecksumError(); #undef MAX_INTERP_HDR }
void PackUnix::unpack(OutputFile *fo) { unsigned const szb_info = sizeof(b_info); unsigned c_adler = upx_adler32(NULL, 0); unsigned u_adler = upx_adler32(NULL, 0); // defaults for ph.version == 8 unsigned orig_file_size = 0; blocksize = 512 * 1024; fi->seek(overlay_offset, SEEK_SET); if (ph.version > 8) { p_info hbuf; fi->readx(&hbuf, sizeof(hbuf)); orig_file_size = get_te32(&hbuf.p_filesize); blocksize = get_te32(&hbuf.p_blocksize); if (file_size > (off_t)orig_file_size || blocksize > orig_file_size) throwCantUnpack("file header corrupted"); } else { // skip 4 bytes (program id) fi->seek(4, SEEK_CUR); } if ((int)(blocksize + OVERHEAD) < 0) throwCantUnpack("blocksize corrupted"); ibuf.alloc(blocksize + OVERHEAD); // decompress blocks unsigned total_in = 0; unsigned total_out = 0; b_info bhdr; memset(&bhdr, 0, sizeof(bhdr)); for (;;) { #define buf ibuf int i; unsigned sz_unc, sz_cpr; fi->readx(&bhdr, szb_info); ph.u_len = sz_unc = get_te32(&bhdr.sz_unc); ph.c_len = sz_cpr = get_te32(&bhdr.sz_cpr); if (sz_unc == 0) // uncompressed size 0 -> EOF { // note: must reload sz_cpr as magic is always stored le32 sz_cpr = get_le32(&bhdr.sz_cpr); if (sz_cpr != UPX_MAGIC_LE32) // sz_cpr must be h->magic throwCompressedDataViolation(); break; } if (sz_unc <= 0 || sz_cpr <= 0) throwCompressedDataViolation(); if (sz_cpr > sz_unc || sz_unc > blocksize) throwCompressedDataViolation(); i = blocksize + OVERHEAD - sz_cpr; if (i < 0) throwCantUnpack("corrupt b_info"); fi->readx(buf+i, sz_cpr); // update checksum of compressed data c_adler = upx_adler32(buf + i, sz_cpr, c_adler); // decompress if (sz_cpr < sz_unc) { decompress(buf+i, buf, false); if (0!=bhdr.b_ftid) { Filter ft(ph.level); ft.init(bhdr.b_ftid); ft.cto = bhdr.b_cto8; ft.unfilter(buf, sz_unc); } i = 0; } // update checksum of uncompressed data u_adler = upx_adler32(buf + i, sz_unc, u_adler); total_in += sz_cpr; total_out += sz_unc; // write block if (fo) fo->write(buf + i, sz_unc); #undef buf } // update header with totals ph.c_len = total_in; ph.u_len = total_out; // all bytes must be written if (ph.version > 8 && total_out != orig_file_size) throwEOFException(); // finally test the checksums if (ph.c_adler != c_adler || ph.u_adler != u_adler) throwChecksumError(); }
void PackUnix::unpackExtent(unsigned wanted, OutputFile *fo, unsigned &total_in, unsigned &total_out, unsigned &c_adler, unsigned &u_adler, bool first_PF_X, unsigned szb_info ) { b_info hdr; memset(&hdr, 0, sizeof(hdr)); while (wanted) { fi->readx(&hdr, szb_info); int const sz_unc = ph.u_len = get_te32(&hdr.sz_unc); int const sz_cpr = ph.c_len = get_te32(&hdr.sz_cpr); ph.filter_cto = hdr.b_cto8; if (sz_unc == 0) { // must never happen while 0!=wanted throwCantUnpack("corrupt b_info"); break; } if (sz_unc <= 0 || sz_cpr <= 0) throwCantUnpack("corrupt b_info"); if (sz_cpr > sz_unc || sz_unc > (int)blocksize) throwCantUnpack("corrupt b_info"); int j = blocksize + OVERHEAD - sz_cpr; fi->readx(ibuf+j, sz_cpr); // update checksum of compressed data c_adler = upx_adler32(ibuf + j, sz_cpr, c_adler); // decompress if (sz_cpr < sz_unc) { decompress(ibuf+j, ibuf, false); if (12==szb_info) { // modern per-block filter if (hdr.b_ftid) { Filter ft(ph.level); // FIXME: ph.level for b_info? ft.init(hdr.b_ftid, 0); ft.cto = hdr.b_cto8; ft.unfilter(ibuf, sz_unc); } } else { // ancient per-file filter if (first_PF_X) { // Elf32_Ehdr is never filtered first_PF_X = false; // but everything else might be } else if (ph.filter) { Filter ft(ph.level); ft.init(ph.filter, 0); ft.cto = (unsigned char) ph.filter_cto; ft.unfilter(ibuf, sz_unc); } } j = 0; } // update checksum of uncompressed data u_adler = upx_adler32(ibuf + j, sz_unc, u_adler); total_in += sz_cpr; total_out += sz_unc; // write block if (fo) fo->write(ibuf + j, sz_unc); if (wanted < (unsigned)sz_unc) throwCantUnpack("corrupt b_info"); wanted -= sz_unc; } }
int PackArmPe::canUnpack() { if (!readFileHeader() || (ih.cpu != 0x1c0 && ih.cpu != 0x1c2)) return false; unsigned objs = ih.objects; isection = new pe_section_t[objs]; fi->seek(pe_offset+sizeof(ih),SEEK_SET); fi->readx(isection,sizeof(pe_section_t)*objs); if (ih.objects < 3) return -1; bool is_packed = ((ih.objects == 3 || ih.objects == 4) && (IDSIZE(15) || ih.entry > isection[1].vaddr)); bool found_ph = false; if (memcmp(isection[0].name,"UPX",3) == 0) { // current version fi->seek(isection[1].rawdataptr - 64, SEEK_SET); found_ph = readPackHeader(1024); if (!found_ph) { // old versions fi->seek(isection[2].rawdataptr, SEEK_SET); found_ph = readPackHeader(1024); } } if (is_packed && found_ph) return true; if (!is_packed && !found_ph) return -1; if (is_packed && ih.entry < isection[2].vaddr) { unsigned char buf[256]; bool x = false; memset(buf, 0, sizeof(buf)); try { fi->seek(ih.entry - isection[1].vaddr + isection[1].rawdataptr, SEEK_SET); fi->read(buf, sizeof(buf)); // FIXME this is for x86 static const unsigned char magic[] = "\x8b\x1e\x83\xee\xfc\x11\xdb"; // mov ebx, [esi]; sub esi, -4; adc ebx,ebx int offset = find(buf, sizeof(buf), magic, 7); if (offset >= 0 && find(buf + offset + 1, sizeof(buf) - offset - 1, magic, 7) >= 0) x = true; } catch (...) { //x = true; } if (x) throwCantUnpack("file is modified/hacked/protected; take care!!!"); else throwCantUnpack("file is possibly modified/hacked/protected; take care!"); return false; // not reached } // FIXME: what should we say here ? //throwCantUnpack("file is possibly modified/hacked/protected; take care!"); return false; }
static void xcheck(size_t poff, size_t plen, const void *b, size_t blen) { ACC_UNUSED(b); if (poff > blen || poff + plen > blen) throwCantUnpack("pointer out of range; take care!"); }